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/FASTOPEN/FASTINIT.ASM | 2970 ++++++++++++++++++++++++++++++++++++ v4.0/src/CMD/FASTOPEN/FASTOPEN.ASM | 2052 +++++++++++++++++++++++++ v4.0/src/CMD/FASTOPEN/FASTOPEN.LNK | 7 + v4.0/src/CMD/FASTOPEN/FASTOPEN.SKL | 28 + v4.0/src/CMD/FASTOPEN/FASTOPEN.TXT | 615 ++++++++ v4.0/src/CMD/FASTOPEN/FASTP.ASM | 131 ++ v4.0/src/CMD/FASTOPEN/FASTSEEK.ASM | 2944 +++++++++++++++++++++++++++++++++++ v4.0/src/CMD/FASTOPEN/FASTSEGS.INC | 20 + v4.0/src/CMD/FASTOPEN/FASTSM.ASM | 145 ++ v4.0/src/CMD/FASTOPEN/MAKEFILE | 47 + 10 files changed, 8959 insertions(+) create mode 100644 v4.0/src/CMD/FASTOPEN/FASTINIT.ASM create mode 100644 v4.0/src/CMD/FASTOPEN/FASTOPEN.ASM create mode 100644 v4.0/src/CMD/FASTOPEN/FASTOPEN.LNK create mode 100644 v4.0/src/CMD/FASTOPEN/FASTOPEN.SKL create mode 100644 v4.0/src/CMD/FASTOPEN/FASTOPEN.TXT create mode 100644 v4.0/src/CMD/FASTOPEN/FASTP.ASM create mode 100644 v4.0/src/CMD/FASTOPEN/FASTSEEK.ASM create mode 100644 v4.0/src/CMD/FASTOPEN/FASTSEGS.INC create mode 100644 v4.0/src/CMD/FASTOPEN/FASTSM.ASM create mode 100644 v4.0/src/CMD/FASTOPEN/MAKEFILE (limited to 'v4.0/src/CMD/FASTOPEN') diff --git a/v4.0/src/CMD/FASTOPEN/FASTINIT.ASM b/v4.0/src/CMD/FASTOPEN/FASTINIT.ASM new file mode 100644 index 0000000..db21b58 --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTINIT.ASM @@ -0,0 +1,2970 @@ + Page 84,132 ; + +TITLE FASTINIT - initialization code for FASTOPEN (May 13, 1988) + +;ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» +; The entire Fastopen component is divided into 5 modules. They are: +; Fastopen initialization routine-1, Fastopen initialization routine-2, +; Fastopen which manages the directory/file cache buffers, the Fastseek +; which manages the cluster information cache buffers and the +; cache buffer which holds both directory and cluster information. +; +; These modules resides in different segments for the reason that they can +; be overlayed conditionally, depending on the user request. For example +; initially all segments are loaded into the memory. If fastopen reature is +; not requested, the segment which contains Fastseek will be overlayed over +; original Fastopen to save space. Segmentation is also usefull when Fastopen +; and Fstseek need to copy into Expanded memory. Following figure shows +; memory map of the FastOpen. +; +; Modules Segment +; +; Ú-------------------¿ +; ³ MAIN ³ CSEG_MAIN +; Ã-------------------´ +; ³ FASTINIT1 ³ CSEG_MAIN +; Ã-------------------´ +; ³ ³ +; ³ FASTOPEN ³ CSEG_OPEN +; ³ ³ +; Ã-------------------´ +; ³ ³ +; ³ FASTSEEK ³ CSEG_SEEK +; ³ ³ +; Ã-------------------´ +; ³ FASTINIT2 ³ CSEG_INIT +; Ã-------------------´ +; ³ ³ +; ³ NAME AND ³ +; ³ EXTENT ³ +; ³ CACHE BUFFERS ³ CSEG_INIT +; ³ ³ +; À-------------------Ù +; +; MAIN: This module provides DOS entry point into FASTOPEN. It also +; dispatch various Fastopen and Fastseek functions. This module is +; in the file FASTOPEN.asm +; +; FASTINIT-1: This module is called INIT_TREE which is also a part of the +; Cseg_Main segment. This basically initializes both +; Name and Extent drive headers, and sets up name and extent +; cache buffers. This module can be found in the file +; FASTINIT.asm +; +; FASTINIT-1: This module is called INIT which is part of the Cseg_Init +; segment. This module parses the user commad, check memory +; requirements, overlay Fastopen and Fastseek code and finally +; installs the Fastopen to be stay resident. This module is +; eventually overlayed by the cache buffers created during the +; buffer initialization by FASTINIT-1 ( See INIT_TREE) +; This module can be found in FASTINIT.asm +; +; FASTOPEN: This module is a collection of four Fastopen functions which +; manage the File/Directory cache buffers. These functions are +; in the file FASTOPEN.asm +; +; FASTSEEK: This module is a collection of six FastSeek functions which +; manage queues associated with the cluster information +; cache buffers. This module is found in the file FASTSEEK.asm. +; +; +; Fastopen Code and Cache buffer Relocation +; ----------------------------------------- +; If user specifies both n and m in the user command and /x, then +; Cseg_Open, Cseg_Seek and Cseg_Init will be copied into a 16K page of the +; Expanded Memory. If only n is specified, then Cseg_Open and Cseg_Init will +; be copied. If only m is specified, then Cseg_Seek and Cseg_init will be +; copied. After this the total size of the segments transferred will be +; deblocked from the low memory to save available user space. +; +; If /x is not specified and only n is specified, then the Cseg_Init will +; moved over to Cseg_Seek which is followed by a deblock of memory. If only +; m is specified, then Cseg_Seek will moved over to Cseg_Open and the +; Cseg_Init will be moved over to Cseg_Seek then deblocks the size Cseg_Open. +; +; WARNING: After every move you have to recalculate the Seg ID of moved +; modules depending on how far it has been displaced and then +; replace the Seg ID in the jump vectors used for accessing +; functions in the moved modules. A wrong Seg ID can cause +; instant System CRASH ...@%+(@!$#@@*&... +; +; Future Enhancements: +; +; 1. Modify Fastopen so that it can be run on removable media (Diskette). +; At present only fixed disk is supported. +; +; 2. Allocate all Extent buffers during initialization. Now they are +; done in run time. This may avoid using flags (-2) for discontinuous +; buffers. Using (-2) requires buffers be filled with '0's during PURGE. +; +; 3. Mark the LRU extent every time buffer is changed, so that the +; the buffers need not be searched during buffer recycling +; +; 4; Currently Fastopen code and cache is kept in one 16K page of the +; Extended Memory. This puts a restriction on the size of the cache +; buffer available in EMS usually about 8K. This can be avoided by +; keeping code and cache buffers in two seperated pages, so that maximum +; of 16K is available for cache buffers. +;ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ +; +IF1 + %OUT ASSEMBLING: FASTINIT - FASTOPEN initialization +ENDIF +NAME FASTINIT + +.XCREF +.XLIST + + +TRUE EQU 0FFFFh ;AN000; +FALSE EQU 0 ;AN000; + +DBCS = FALSE ;AN000; +Installed = TRUE ;AN000; + +IFNDEF DEBUG + DEBUG = FALSE +ENDIF + +INCLUDE dosmac.inc ;AN000; +INCLUDE vector.inc ;AN000; +INCLUDE filemode.inc ;AN000; +INCLUDE mult.inc ;AN000; +include version.inc + +.LIST +.CREF + +INCLUDE fastsegs.inc ;AN000; +INCLUDE fastopen.inc ;AN000; +INCLUDE SYSCALL.INC ; ;AN000; + +;----------------------------------------------------------------------- +; EQUATES +;----------------------------------------------------------------------- +Top_mem EQU 02h ;Top of memory index in PSP ;AN000; +Min_entry_num EQU 10 ;minimum name cache entries ;AN000; +Max_entry_num EQU 999 ;maximum name cache entries ;AN000; +Default_names EQU 34 ;default name cache entries ;AN000; +Debug EQU 0 ;for callinstall ;AN000; +Len_source_xname EQU 4 ;used for xname translate ;AN000; +No_siblings EQU -1 ;indicate no siblings ;AN000; +No_child EQU -1 ;indicate no children ;AN000; +No_backward EQU -1 ;no backward pt yet ;AN000; +Max_drives EQU 24 ;maximum number of drives allowed ;AN000; + + +; ----------------- MESSAGE EQUATES ------------------------------------- + +Not_enough_mem EQU 2 ;AN000; +Invalid_switch EQU 3 ;AN000; +Install1 EQU 4 ;AN000; +Already_install EQU 5 ;AN000; +Incorrect_param EQU 6 ;AN000; +Too_many_entries EQU 7 ;AN000; +Dup_drive EQU 8 ;AN000; +Invalid_extent EQU 11 ;AN000; +Invalid_name EQU 12 ;AN000; +Ems_failed EQU 13 ;AN000; +Ems_not_install EQU 14 ;AN000; +Invalid_drive EQU 15 ;AN000; +No_page_space EQU 16 ;AN000; +Bad_Use_Message EQU 17 +Many_Ext_Entries EQU 18 +Many_Name_Entries EQU 19 + + +;------------ E M S SUPPORT EQUATES ------------------------------- + +EMS_GET_STATUS EQU 40H ;AN000; +EMS_GET_NUM_PAGES EQU 42H ;AN000; +EMS_ALLOC_PAGES EQU 43H ;AN000; +EMS_MAP_HANDLE EQU 44H ;AN000; +EMS_GET_VERSION EQU 46H ;AN000; +EMS_SAVE_STATE EQU 47H ;AN000; +EMS_RESTORE_STATE EQU 48H ;AN000;;AN000; +EMS_PAGE_SIZE EQU 4FH ;AN000;;AN000; +EMS_2F_HANDLER EQU 1BH ;AN000;;AN000; + +IF NOT IBMCOPYRIGHT + +EMS_GET_COUNT EQU 5801H + +ELSE + +EMS_GET_COUNT EQU 5800H ;AN000; + +ENDIF + +EMS_GET_FRAME_ADDR EQU 5800H ;AN000; +EMS_HANDLE_NAME EQU 53H +EMS_INT EQU 67H ;AN000; +SINGLE_SEGMENT EQU 1 ;AN000; + + +;-------------------- STRUCTURES --------------------------------- + +PAGE_FRAME_STRUC STRUC ; EMS page frame structure ;AN000; + + PAGE_SEG DW ? ;EMS page segment ;AN000; + PAGE_NUM DW ? ;EMS page number (only one page is used) ;AN000; + +PAGE_FRAME_STRUC ENDS + +BUFFER_ENTRY_SIZE EQU TYPE PAGE_FRAME_STRUC + + +SUB_LIST STRUC ; Message handler sublist structure ;AN000; + DB 11 ; ;AN000; + DB 0 ; ;AN000; +DATA_OFF DW 0 ; offset of data to be inserted ;AN000; +DATA_SEG DW 0 ; offset of data to be inserted ;AN000; +MSG_ID DB 0 ; n of %n ;AN000; +FLAGS DB 0 ; Flags ;AN000; +MAX_WIDTH DB 0 ; Maximum field width ;AN000; +MIN_WIDTH DB 0 ; Minimum field width ;AN000; +PAD_CHAR DB 0 ; character for pad field ;AN000; +SUB_LIST ENDS ;AN000; + +;------------------------------------------------------------------------------- +; Following two segments are used to define external variable that +; are defined in two other segments. +;------------------------------------------------------------------------------- + +CSEG_OPEN SEGMENT PARA PUBLIC 'CODE' ; Cseg_Open segment + EXTRN Open_name_cache_seg:word + EXTRN Open_Name_Drive_Buff:word + EXTRN End_Open:byte + EXTRN Chk_Flag:word + EXTRN VECTOR_LOOKUP:dword ; jump vector inside Cseg_Main to make + ; a FAR call to Fopen LookUp function within + ; the segment +CSEG_OPEN ENDS + + +CSEG_SEEK SEGMENT PARA PUBLIC 'CODE' ; Cseg_Seek segment + EXTRN Seek_Extent_Drive_buff:word + EXTRN Seek_Name_Drive_buff:word + EXTRN Seek_Name_Cache_buff:word + EXTRN Seek_Name_Cache_Seg:word + EXTRN Seek_Num_Of_Drives:word + EXTRN Seek_Total_Ext_Count:word + EXTRN Seek_Total_Name_Count:word + EXTRN End_Seek:byte + EXTRN Check_Flag:word + EXTRN VECTOR_DELETE:dword ; jump vector inside Cseg_Seek to make + ; a FAR call to FSeek Delete function within + ; the segment +CSEG_SEEK ENDS + + + + + +;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ +CSEG_MAIN SEGMENT PARA PUBLIC 'CODE' ; MAIN segment + +; This segment is a continuation of the Cseg_Main segment in Fastopen.asm +; and contains code to initializes name and extent drive buffers +;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ +ASSUME CS:cseg_main,DS:nothing,SS:stack,ES:nothing + +EXTRN MAIN:FAR ;AN000; + +IF BUFFERFLAG + +extrn restore_page_state:near ; HKN 8/25/88 + +extrn ems_save_handle1:word ; HKN +extrn ems_page_number:word ; HKN + +ENDIF + +EXTRN Main_Total_Ext_Count:word ;AN000; +EXTRN Main_Total_Name_Count:word ;AN000; +EXTRN Main_Name_Drive_Buff:word ;AN000; +EXTRN Main_Name_Cache_Buff:word ;AN000; +EXTRN Main_Name_Cache_Seg:word ;AN000; +EXTRN Main_Parambuff:byte ;AN000; +EXTRN Main_extent_drive_Buff:word ;AN000; +EXTRN Main_Num_Of_drives:word ;AN000; +EXTRN Main_Ext_Count:word ;AN000; +EXTRN Main_Ext_Cache_Size:word ;AN000; +EXTRN Main_EMS_FLAG:word ;AN000; +EXTRN Main_Res_Segs:word ;AN000; +EXTRN Main_EMS_PAGE_SEG:word ;AN000; +EXTRN Main_EMS_PAGE_SIZE:word ;AN000; + +EXTRN FOPEN_Insert:dword ;AN000; +EXTRN FOPEN_Update:dword ;AN000; +EXTRN FOPEN_Delete:dword ;AN000; +EXTRN FOPEN_Lookup:dword ;AN000; +IF BUFFERFLAG +EXTRN FOPEN_Purge:dword +ENDIF + +EXTRN FSEEK_Open:dword +EXTRN FSEEK_Close:dword +EXTRN FSEEK_Insert:dword +EXTRN FSEEK_Delete:dword +EXTRN FSEEK_Lookup:dword +EXTRN FSEEK_Truncate:dword +EXTRN FSEEK_Purge:dword + +;************************************************************************* +; +;SUBROUTINE: INIT_TREE (FASTINIT-1) +; +;FUNCTION: This routine builds 'N' name directory buffers under each drive +; header. The second half of this routine initializes the extent +; drive headers and makes the Fastopen code resident. +; +;INPUT: Drive_cache_header, End_Caches +; +;OUTPUT: Name_cache and Extent Cache entries installed for every +; drive requested. +; +;************************************************************************* + IF ($-Cseg_Main) MOD 16 ;AN000; + ORG ($-Cseg_Main)+16-(($-Cseg_Main) MOD 16) ;AN000; + ENDIF ;AN000; +End_Main1 label word ;AN000; + + +INIT_TREE: + mov ax,cseg_Main ;get addressiblity to ;AN000; + mov ds,ax ;DS --> Cseg_Main ;AN000; + ASSUME ds:cseg_Main ;AN000; + + cmp Main_Total_Name_Count,0 ;initialize Name drive headers?? ;AN000; + je Init_Ext_Drive_Hdrs ;no, init extent drive headers ;AN000; + +;----------------------------------------------------------------------------- +; Following code adds 'n' directory entry buffers to each Name Drive headers, +; depending on the value of 'n' specified with each drive ID +;----------------------------------------------------------------------------- + mov si,Main_Name_Drive_Buff ;SI-->first Name drive cache buff + mov bx,Main_Name_Cache_Buff ;BX-->Name cache buffer + xor dx,dx + xor ax,ax + + mov ax,Main_Name_Cache_Seg ;get addresability to CSeg_Init + mov ds,ax ;DS=addressablity to Cseg_Init + ASSUME ds:cseg_Init + +Set_Up_Cache: + mov [si].DCH_LRU_ROOT,bx ;set to point to first name + mov [si].DCH_NAME_BUFF,bx ;set to point to first name + mov cx,[si].DCH_num_entries ;get number of name records + +;----------------------------------------------------------------------------- +; set up MRU and LRU pointers +; AX points to last name record +; BX points to current name record +; DX points to next name record +;----------------------------------------------------------------------------- + mov [bx].nMRU_ptr,-1 ;make first MRU -1 + jmp short set_start + +Set_Up_Names: + mov [bx].nMRU_ptr,ax ;set up MRU + add ax,size name_record + +Set_Start: + mov [bx].nChild_ptr,no_child ;no children or siblings + mov [bx].nsibling_ptr,no_siblings ; right now + mov [bx].nBackward_ptr,no_backward + push es + push di + push ax + + push ds + pop es ;ES-->name cache buffer + ASSUME es:Cseg_Init + + mov ax, ' ' + mov di, bx + add di, nCmpct_Dir_Info ;blank out the Dir name area + stosb ;the directory buffer + stosw + stosw + stosw + stosw + stosw + + pop ax + pop di + pop es + + mov dx,bx ;get name offset + add dx,size name_record ;get start of next name + dec cx ;decrement num_entries + jcxz get_next_drive ;if zero - get next drive + mov [bx].nLRU_ptr,dx ;LRU pointer - next name + add bx,size name_record ; + jmp set_up_names + +Get_Next_Drive: + mov [bx].nLRU_ptr,-1 ;LRU pointer - next name + + mov [si].DCH_MRU_ROOT,bx ;set to point to last name + mov bx,dx ;get pointer to next name + cmp [si].dch_sibling_ptr,no_siblings ;is there any more to set up?? + jz Init_Ext_Drive_Hdrs ; no - set extent drive headers + add ax,size name_record ; yes - get next name directory buffer + add si,size drive_cache_header ;point to next drive header + jmp set_up_cache + + +;---------------------------------------------------------------------------- +; The following section initializes the Extent Drive Headers. +; DS has addressability to MAIN segment (CSEG_MAIN) and ES has +; addressability to Cache buffer segment (CSEG_INIT) +;---------------------------------------------------------------------------- +Init_Ext_Drive_Hdrs: + mov ax,cseg_Main ;AN000; + mov ds,ax ;DS-->Cseg_Main ;AN000; + ASSUME ds:cseg_Main ;AN000; + ;AN000; + cmp Main_Total_Ext_Count,0 ;initialize extent drive buffers ?? ;AN000; + jne init_extent_cache ;yes - continue + jmp Init_exit ;no - exit ;AN000; + +;============================================================================ +; Fill extent cache buffer with zeros. Otherwise a (-2) left in the buffer +; could generate a wrong Free buffer pointer since (-2) is the free buffer +; mark. + +Init_Extent_Cache: + mov cx, Main_Ext_Cache_Size ; CX = extent buffer size ;AN000; + mov si,Main_Extent_Drive_Buff ; SI-->start of extent cache buff ;AN000; + push ds ;AN000; + mov ax,Main_Name_Cache_Seg + mov ds,ax ; DS-->new init seg (init segment ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov al,0 ; pattern "0" ;AN000; + +Next_Byte: ; may be in Extended memory) + mov [si],al ;AN000; + inc si ;AN000; + LOOP next_byte ;AN000; + pop ds ; retore original init seg ID ;AN000; +;============================================================================ + + +Init_Set_Cache: + mov si,Main_Extent_Drive_Buff ; SI-->first extent drive header ;AN000; + mov cx,Main_num_of_drives ; number of drives + mov dx,0 ; drive counter + lea di,Main_ParamBuff ; DS:DI-->parameter buff contains ;AN000; + ; drive ID and number of extents ;AN000; + mov es,Main_name_cache_seg ; ES = addressability to Cseg_Init ;AN000; + ASSUME es:Cseg_Init ; ;AN000; + ;AN000; +INIT_LOOP: ; ES:SI-->cache buffer ;AN000; + push cx ; save counter ;AN000; + add di,dx ; points to drive ID of this driv ;AN000; + xor ax,ax ;AN000; + mov ax,[di+2] ; get Extent Count ;AN000; + cmp ax, -1 ; any extent under this drive ?? ;AN000; + je skip_this_drive ; no - dont create header for this ;AN000; + ; this drive + mov ax,0 ; *** for debugging sequence count + mov es:[si].EXTENT_COUNT,ax ; *** use this area for sequence counting + xor ax,ax ;AN000; + mov ax,[di] ; get drive ID from drive ID buff ;AN000; + mov es:[si].DRIVE_NUMBER,ax ; save drive ID in drive header ;AN000; + mov bx, size Drive_Header ;AN000; + add bx,si ; BX-->Free area ;AN000; + mov es:[si].FREE_PTR,bx ; pointing to free area ;AN000; + ;AN000; + mov es:[si].MRU_HDR_PTR,-1 ; mark OPEN QUEUE empty ;AN000; + mov es:[si].CLOSE_PTR,-1 ; make CLOSE QUEUE empty ;AN000; + xor ax,ax ;AN000; + mov ax,[di+2] ; get extent count (n) ;AN000; + mov cx, size Extent_Header ; get extent size ;AN000; + mul cx ; AX=total cache for this drive ;AN000; + mov es:[si].BUFF_SIZE,ax ; save it as initial available size ;AN000; + mov es:[si].FREE_SIZE,ax ; save it as initial free size + add ax, size Drive_Header ; (2/9/88) + add ax,si ; AX-->offset to next drive hdr ;AN000; + mov es:[si].Next_Drv_hdr_Ptr,ax ; save next drive header ptr in ;AN000; + ; current drive header ;AN000; + mov bx,ax ;AN000; + mov ax,si ; save current header pointer ;AN000; + mov si,bx ; DS:SI-->next drive header ;AN000; + ;AN000; +SKIP_THIS_DRIVE: ;AN000; + add dx,4 ; update index to next drive/extent ;AN000; + pop cx ; restore loop count ;AN000; + LOOP init_loop ; repeat for next drive number ;AN000; + ;AN000; + mov si,ax ;AN000; + mov es:[si].Next_Drv_hdr_Ptr,-1 ; mark current header as last + ; drive header +;---------------------------------------------------------------------------- +; Close handles 0 - 4 +;---------------------------------------------------------------------------- + mov bx,0 +Handle_Loop: + mov ah,03EH + INT 21H + inc bx + cmp bx,5 + jne Handle_Loop + +;---------------------------------------------------------------------------- +; Get PSP segment and find the program environment segment and deallocate +; the environment space. +;---------------------------------------------------------------------------- +INIT_EXIT: + push ds + mov si,0081H + mov ah,62H + INT 21H ; get program PSP segment ;AN000; + + mov ds,bx ; DS = PSP segment ;AN000; + mov si,02CH ; SI-->address of enviroment segment + mov ax,[si] ; AX = environment seg id + cmp ax,0 ; environment present ?? + je dont_dealloc ; no - dont deallocate + mov es,ax + mov ah,49H + INT 21H ; deallocate environment +Dont_Dealloc: + pop ds ; restore DS + +;---------------------------------------------------------------------------- +; Keep resident the Fastopen code and cache buffers. The size of the resident +; area is in (Main_Res_Segs). Size may vary depending on whether Fastopen or +; Fastseek or both or extent memory is specified. +;---------------------------------------------------------------------------- + +IF BUFFERFLAG + + call restore_page_state ; HKN 8/25/88 + +ENDIF + + mov ah,KEEP_PROCESS ;remain resident + mov al,0 ;return code + mov dx,Main_Res_Segs ;size of area in paragraph + INT 21h ;keep resident and then return + ;control to DOS + +;---------------------------------------------------------------------------- +; Calculate the size of the MAIN module in bytes. First potion of this +; segment can be found in the Fastopen.asm +;---------------------------------------------------------------------------- + IF ($-Cseg_Main) MOD 16 ;AN000; + ORG ($-Cseg_Main)+16-(($-Cseg_Main) MOD 16) ;AN000; + ENDIF ;AN000; +End_Main label word ;AN000; + + +CSEG_MAIN ENDS ; End of Cseg_Main segment +page + + +;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ + +CSEG_INIT SEGMENT PUBLIC PARA 'CODE' + +;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ + ASSUME cs:cseg_init,ds:cseg_init,ss:stack,es:cseg_init + + EXTRN SYSPARSE:NEAR ;AN000; + EXTRN SYSLOADMSG:NEAR ;AN000; + EXTRN SYSDISPMSG:NEAR ;AN000; + +IF BUFFERFLAG + extrn save_ems_page_state:far ; HKN 8/25/88 +ENDIF + + +;---------------------------------------------------------------------------- +; The cache buffers start from the first location of Cseg_Init. +; First portion is the NAME DRIVE HEADERS, which is followed by +; NAME CACHE BUFFER, which is followed by EXTENT DRIVE HEADER. Under each +; extent drive header its cache buffer. 24 Name drive buffers are allocated +; during assembly time. Remaining drive and cache buffers are allocated +; during run time. Eventhough 24 name cache buffers are allocated during +; assembly time, this number may be reduced to the specified number of drive +; numbers during run time by overlaying other drive buffers over the unused ones. +; The initialization code will be overlayed by name and extent cache buffs +; during second half of the initialization which is in the MAIN module (see INit_Tree). +;----------------------------------------------------------------------------- + +Drive_header_start label byte ;Name cache drive buffer +Drive_Cache Drive_Cache_Header max_drives DUP (<>) ; header for 24 drives are reserved + +;----------------------------------------------------------------------------- +; Anything below this point will be overlayed by the Cache Buffers +; MSG retriever is placed after Cache buffer, so that the area can be +;----------------------------------------------------------------------------- +;============================================================================= +; Non_Resident Data Area +;============================================================================= +INIT_VECTOR DD INIT_TREE ;jump vector to INIT_TREE ;AN000; +MAIN_VECTOR DD MAIN ;entry point to MAIN routine ;AN000; +source_xname DB " :\",0 ;used for xname translate ;AN000; +target_xname DB 65 DUP (0) ;used for xname translate ;AN000; +user_drive db 0 ;current user drive ;AN000; +psp_seg dw 0 ;segment of psp ;AN000; +stack_seg_start dw 0 ;segment of temporary stack ;AN000; +stack_seg_end dw 0 ;AN000; +num_of_drives dw 0 ;number of user specified drives ;AN000; +Ext_Mem dw 0 ;=1 if exteded memory is enabled ;AN000; +drive_id db " :",0 ;AN000; +Parambuff db 50 dup (0) +Parmbuff_Ptr dw 0 ;AN000; +FRAME_COUNT dw 0 ;EMS frame count + +IF IBMCOPYRIGHT + +FRAME_BUFFER DB 30h DUP(0) ;EMS frame buffer + +ELSE + +FRAME_BUFFER DB 100h DUP(0) ; EMS frame buffer + +ENDIF + +IF BUFFERFLAG +FST_PAGE DW 0,0 ; holds the second highest page above 640k +ENDIF + +Cmdline_buff db 135 dup (0) ;command line buffer ;AN000; +name_cache_seg dw Cseg_Init ;default to Init1 seg ;AN000; +Ext_Count dw 0 ;total name extent entries ;AN000; +extent_drive_Buff dw 0 ;ptr to extent drive ;AN000; +name_cache_Buff dw 0 ;pointer to Name cache buffer ;AN000; +EMS_FLAG dw 0 ;EMI flag 1= if EMI is enabled ;AN000; +CHECK_QUEUE dw 0 ; = 1 if analyser is activated +RES_SEGS dw 010H+020H ;PSP SIZE + STACK SIZE resident segment size +EMS_PAGE_SEG DW 0 ;EMS code page segment ID ;AN000; +EMS_PAGE_NUM DW 0 ;EMS physical page number ;AN000; +Total_Ext_Count DW 0 ;Total extent entry count ;AN000; +Total_Name_Count DW 0 ;Total Name entry count ;AN000; +Total_Cache_Size DW 0 ;Total cache buffer size (name+extent) buffer ;AN000; +Name_Cache_Size DW 0 ;Total name cache size (header + entry buffs) +Name_Count DW 0 ;name entry count +Name_Drive_Buff DW 0 ;name driver buffer address ;AN000; +Ext_Cache_Size DW 0 ;extent buffer size ;AN000; +Open_SegID DW 0 ;SegId of Cseg_Open after relocation ;AN000; +Seek_SegID DW 0 ;SegId of Cseg_Seek " " ;AN000; +Init_SegID DW 0 ;SegId of Cseg_Init " " ;AN000; +MAIN_Size DW 0 ;size of Cseg_Main in Paragraph ;AN000; +OPEN_Size DW 0 ;size of Cseg_Open in paragraph ;AN000; +SEEK_Size DW 0 ;size of Cseg_Seek in paragraph ;AN000; + +;-----------------------------------------------------------------------; +; EMS Support ; +;-----------------------------------------------------------------------; +EXT_HANDLE DW ? ; EMS handle for reference ;AN000; +EMS_PAGESIZE DW ? ; EMS handle for reference ;AN000; +EMS_FRAME_ADDR DW ? ; EMS handle for reference ;AN000; +CURR_EMS_PAGE DB ? ; Current EMS page number ;AN000; +HANDLE_NAME DB 'FASTOPEN',0 ; EMS handle name ;AN000; + +IF BUFFERFLAG +SAVE_MAP_ADDR DD ? ; HKN 8/25/88 +ENDIF + +;--------------------------------------------------------------------------- +; PARSER Support +;--------------------------------------------------------------------------- +CURRENT_PARM DW 81H ;POINTER INTO COMMAND OF CUREENT OPERANT ;AN000; +NEXT_PARM DW 0 ;POINTER INTO COMMAND OF NEXT OPERAND ;AN000; +ORDINAL DW 0 ;ORDINAL NUMBER OF MAIN PARSER LOOP ;AN000; +ORDINAL1 DW 0 ;ORDINAL NUMBER OF COMPLEX ITEM LOOP ;AN000; +PREV_TYPE DB 0 ;PREVIOUS POSITIONAL PARAMETER TYPE + +;--------------------------------------------------------------------------- +; PRINT_STDOUT input parameter save area +;---------------------------------------------------------------------------- +SUBST_COUNT DW 0 ;message substitution count ;AN000; +MSG_CLASS DB 0 ;message class ;AN000; +INPUT_FLAG DB 0 ;Type of INT 21 used for KBD ;AN000; +MSG_NUM DW 0 ;message number ;AN000; + + +;---------------------------------------------------------------------------- +; Following three sublists are used by the Message Retriever +;---------------------------------------------------------------------------- +SUBLIST1 LABEL DWORD ;SUBSTITUTE LIST 1 + DB 11 ;sublist size ;AN000; + DB 0 ;reserved ;AN000; + DD 0 ;substition data Offset ;AN000; + DB 1 ;n of %n ;AN000; + DB 0 ;data type ;AN000; + DB 0 ;maximum field width ;AN000; + DB 0 ;minimum field width ;AN000; + DB 0 ;characters for Pad field ;AN000; + + +SUBLIST2 LABEL DWORD ;SUBSTITUTE LIST 2 + DB 11 ;sublist size ;AN000; + DB 0 ;reserved ;AN000; + DD 0 ;substition data Offset ;AN000; + DB 2 ;n of %n ;AN000; + DB 0 ;data type ;AN000; + DB 0 ;maximum field width ;AN000; + DB 0 ;minimum field width ;AN000; + DB 0 ;characters for Pad field ;AN000; + + + +;-------------------------------------------------------------------------- +; PARSER Control Blocks and Buffers +;-------------------------------------------------------------------------- + +PARMS label word + DW parmsx ;AN000; + DB 1 ; number of delemeters ;AN000; + DB 1 ; extra delimeters length ;AN000; + DB "=" ; extra delimeter expected ;AN000; + DB 0 ; extra end of line length ;AN000; + DB 0 ;AN000; + + +PARMSX label byte ;AN000; +par_min DB 1 ; min, max positional operands allowed ;AN000; +par_max DB 2 ; min, max positional operands allowed ;AN000; + DW Pos1 ; offset into positonal-1 control block ;AN000; + DW Pos2 ; offset into positonal-1 control block ;AN000; +par_sw DB 1 ; one switch ;AN000; + DW Switch ; offset into switch-1 control bloc ;AN000; + DB 0 ; no keywords ;AN000; + DB 0 ; 0 ;AN000; + + + +;------------------ POS2 CONTROL BLOCK -------------------------------------- + +POS1 label word ; positional-1 control definition +Pos1Type DW 0100H ; control type flag (drive only) ;AN000; + DW 0 ; function flags ;AN000; + DW Result ; offset into result buffer ;AN000; + DW value_pos1 ; offset value list buffer ;AN000; + DB 0 ; number of keyword/switch synonyms ;AN000; + + +Value_Pos1 label byte ; postional parameter value expected ;AN000; + DB 0 ; no values expected ;AN000; + + + +;---------------- POS1 CONTROL BLOCK ---------------------------------------- + +POS2 label word ; positional-2 control definition ;AN000; +Pos2Type DW 08502H ; Control type (complex/integer/drive/ ;AN000; + ; repeat) ;AN000; + DW 0 ; function flags ;AN000; + DW Result ; offset into result buffer ;AN000; + DW value_pos2 ; offset value list buffer ;AN000; + DB 0 ; number of keyword/switch synonyms ;AN000; + +Value_Pos2 label byte + DB 0 ; either (n) or (m) will be returned + + + +;--------------- RESULT BUFFER --------------------------------------------- + +RESULT label byte ; postional2 parameter result buffer ;AN000; +PosType DB ? ; type of operand returned ;AN000; +Postag DB ? ; type of item tage returned ;AN000; +synonym DW ? ; offset into synonyms returned ;AN000; +valuelo DW ? ; space for drive number/integer/strin ;AN000; +valuehi DW ? ;AN000; + + +;---------------- SWITCH CONTROL BLOCK ------------------------------------------ + +SWITCH label word ; switch control definition + DW 0 ; no match flag ;AN000; + DW 0 ; no function flags ;AN000; + DW Result ; offset into result buffer ;AN000; + DW value_sw1 ; offset value list buffer ;AN000; + DB 1 ; number of keyword/switch synonyms ;AN000; +E_Switch DB "/X" ; /X option for extended memory access ;AN000; + DB 0 ;AN000; + + +Result_sw1 label byte ; switch parameter result ;AN000; + DB ? ; type of operand returned ;AN000; + DB ? ; type of item tage returned ;AN000; +Swval DW ? ; offset into synonyms returned ;AN000; + DB ? ; switch value ;AN000; + + +Value_sw1 label byte ; switch parameter value expected ;AN000; + DB 0 ; no values expected ;AN000; + + + + + + + +;----------------------------------------------------------------------------- +; INIT (FASTINIT-2) +;----------------------------------------------------------------------------- +; +;SUBROUTINE: INIT +; +;FUNCTION: Performs FASTOPEN initialization function +; +; +;NOTE: This routine is the starting routine of FASTOPEN +; +;----------------------------------------------------------------------------- + +START: + ; on entry DS and ES -->PSP ;AN000; + push cs ; DS-->Cseg_Init ;AN000; + pop ds ;AN000; + ASSUME ds:cseg_init ;AN000; + mov psp_seg,es ; save PSP segment for later use ;AN000; + push cs ;AN000; + pop es ; ES-->Cseg_Init ;AN000; + ASSUME es:cseg_init ;AN000; + + CALL SYSLOADMSG ; Preload messages ;AN000; + jnc Parse_cmd_line ; If no error, parse command line ;AN000; + + mov ax,1 ;AN000; + CALL SYSDISPMSG ; display error ;AN000; + + mov ah,04ch ; Terminate ;AN000; + mov al,0 ; Errorlevel 0 (Compatible) ;AN000; + INT 021h ; exit to DOS + +Parse_Cmd_Line: ;AN000; + CALL PARSE ;Parse command line ;AN000; + lea si,parambuff ;drive ID buff address ;AN000; + mov ax,Total_name_Count ; ;AN000; + mov ax,Total_ext_Count ;AN000; + mov ax,num_of_drives ;AN000; + mov ax,ext_mem ;AN000; + jnc Check_Installed ;no, check if Fastopen already installed + jmp error_exit ;yes - exit ;AN000; + +Check_Installed: + CALL CHECK_INSTALL ; Fastopen installed ?? + jnc Save_SegIDs ; no - save segment IDs + jmp error_exit ; yes - exit + +;----------------------------------------------------------------------------- +; Set seg IDs of three segments. +;----------------------------------------------------------------------------- +Save_SegIds: + mov Open_SegID, Cseg_Open ;AN000; + mov Seek_SegID, Cseg_Seek ;AN000; + mov Init_SegID, Cseg_Init ;AN000; + +;----------------------------------------------------------------------------- +; Compute the size of segments and cache buffers. Setup a temporary stack +; to be used by the second half of initilization. +;----------------------------------------------------------------------------- + CALL CHECK_MEM ;See if we have enough memory ;AN000; + jnc chk_extended_mem ;yes, check for extended memory ;AN000; + jmp error_exit ;no - display not enough mem msg ;AN000; + +;----------------------------------------------------------------------------- +; Check if Extended Memeory is specified. If true, check if Extended memory is +; available. Get segid of one extended memory page. +;----------------------------------------------------------------------------- +Chk_Extended_Mem: + cmp ext_mem,1 ; enable EMS ?? ;AN000; + jne Set_Data_Areas ; no, set data areas ;AN000; + + CALL SET_EMS ; set expanded memory ;AN000; + jnc Set_Data_Areas ; if no error ;AN000; + jmp error_exit ; error exit ;AN000; + +;------------------------------------------------------------------------------ +; Copy Data and segid of Init segments to Main, Open and Seek segments. +; If code is relocated, segids have to be adjusted later. (See Adjust_SegID) +;------------------------------------------------------------------------------ +Set_Data_Areas: + CALL COPY_DATA ; copy data to other segments ;AN000; + +;----------------------------------------------------------------------------- +; Relocate code to extended memory if extended memory is specified or +; relocate in lower memory itself. +;----------------------------------------------------------------------------- +Relocate_Code: + CALL RELOCATE_SEGMENT ; Relocate the code cnd buffers ;AN000; + +;----------------------------------------------------------------------------- +; Adjust the segids and jump vectors in other segments after code relocation +;----------------------------------------------------------------------------- + CALL ADJUST_SEGIDS ; adjust segment ids after relocation ;AN000; + +;----------------------------------------------------------------------------- +; Display FASTOPEN INSTALLED message. This must be done prior to the actual +; installation. +;----------------------------------------------------------------------------- +Disp_Install_Msg: ; display FASTOPEN installed message + MOV AX,INSTALL1 ; message number ;AN000; + MOV MSG_NUM,AX ; set message number ;AN000; + MOV SUBST_COUNT,0 ; no message ;AN000; + MOV MSG_CLASS,-1 ; message class ;AN000; + MOV INPUT_FLAG,0 ; no input ;AN000; + CALL PRINT_STDOUT ; show message ;AN000; + +;----------------------------------------------------------------------------- +; Install Fastopen +;----------------------------------------------------------------------------- + CALL INSTALL_FASTOPEN ; Install Fastopen ;AN000; + jnc Setup_Stack ; Installed Ok, setup stack ;AN000; + jmp error_exit ; error - exit + + +;---------------------------------------------------------------------------- +; Set Stack Values. This stack is used by the cache buffer initilization +; portion of the code. This stack area will be eventually overlayed and +; wont be used by either Fastopen or Fastseek functions in MAIN module. +;---------------------------------------------------------------------------- +SETUP_STACK: + nop ;AN000; + CLI ;no interrupts allowed during stach change ;AN000; + mov SS,Stack_Seg_Start ;set up new stack ;AN000; + mov SP,0 ; ;AN000; + STI ;interrupts ok now ;AN000; + jmp INIT_VECTOR ;Jump to Cseg_Main to do second + ;phase of the initialization +ERROR_EXIT: + mov al,1 ;set up return code + mov ah,exit ;set function code + INT INT_COMMAND ;exit to DOS + + + + +;---------------------------------------------------------------------------- +; CHECK_INSTALL +;---------------------------------------------------------------------------- +; Input: None +; +; Output: +; IF Carry = 0 - Fastopen is not already installed +; +; IF Carry = 1 - Fastopen is already installed +; +;---------------------------------------------------------------------------- +; Use CALLINSTALL macro to see if FASTOPEN is already installed. +; If carry flag set then FASTOPEN is installed. In this case display +; Already Installed message. +;---------------------------------------------------------------------------- + +CHECK_INSTALL PROC NEAR + + push ax ;save every registers that may + push bx ;be destroyed by DOS + push cx + push dx + push si + push di + push bp + + push ds + mov bx, 1 ;Fastopen function code + mov si, -1 ;special check install code + CALLINSTALL fastopencom,multdos,42 ;see if fastopen installed + pop ds + jc Install_Msg ;yes, display already installed + ;message +;---------------------------------------------------------------------------- +; Check if Fastseek function is enabled. If true display Installed message +;---------------------------------------------------------------------------- ;AN000; + push ds ;AN000; + mov si, -1 ;special check installed code + mov bx, 2 ;for Fastseek + CALLINSTALL fastopencom,multdos,42 ;see if fastopen installed ;AN000; + pop ds ;AN000; + jnc Chk_Install_Exit ; no, exit ;AN000; + +Install_Msg: ;installed previously display message + MOV AX,ALREADY_INSTALL ;message number ;AN000; + MOV MSG_NUM,AX ;set message number ;AN000; + MOV SUBST_COUNT,0 ;no message substitution ;AN000; + MOV MSG_CLASS,-1 ;message class ;AN000; + MOV INPUT_FLAG,0 ;no input ;AN000; + CALL PRINT_STDOUT ;show message "Already Installed" + stc + +Chk_Install_Exit: + pop bp ;restore registers + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret ;return + +CHECK_INSTALL ENDP + + + + + +;---------------------------------------------------------------------------- +; INSTALL_FASTOPEN +;---------------------------------------------------------------------------- +; Input: Addrss of entry point to Fastopen resident code +; +; Output: +; IF Carry = 0 +; Entry point to FASTOPEN resident code set +; +; IF Carry = 1 Error +; +; Calls: none +;---------------------------------------------------------------------------- +; Use CALLINSTALL macro to see if FASTOPEN is already installed. +; If FASTOPEN is not installed, install it. +; If carry flag set then FASTOPEN is installed. In this case display +; already installed message. +;---------------------------------------------------------------------------- + +INSTALL_FASTOPEN PROC NEAR + + push ax ;Save every registers,point reg since + push bx ;DOS may destroy it. + push cx + push dx + push si + push di + push bp + + cmp Total_Name_Count, 0 ;FastOpen enabled ?? ;AN000; + je Install_Ext ;no - jump + + push ds ;yes - install fastopen + mov bx, 1 ;tell DOS that this is the + lds si,Main_Vector + CALLINSTALL fastopencom,multdos,42 ;see if fastopen installed + pop ds + jc Install_Exit ;error - exit + +;---------------------------------------------------------------------------- +; Check if Fastseek functions are enabled. If true, pass MAIN routine entry +; point and the Fastseek enabled information to DOS +;---------------------------------------------------------------------------- ;AN000; +Install_Ext: + cmp Total_Ext_Count, 0 ; Fastseek enabled ?? ;AN000; + jne ext_install ; yes - install fastseek ;AN000; + clc ;AN000; + jmp short Install_Exit ; no, exit ;AN000; + +Ext_Install: + push ds ;AN000; + mov bx, 2 ;tell DOS that this is the ;AN000; + lds si,Main_Vector ;fastseek entry point ;AN000; + CALLINSTALL fastopencom,multdos,42 ;see if fastopen installed ;AN000; + pop ds ;AN000; + jnc short install_exit + jmp short install_exit + +Installx_Msg: ;installed previously display message + MOV AX,ALREADY_INSTALL ;message number ;AN000; + MOV MSG_NUM,AX ;set message number ;AN000; + MOV SUBST_COUNT,0 ;no message substitution ;AN000; + MOV MSG_CLASS,-1 ;message class ;AN000; + MOV INPUT_FLAG,0 ;no input ;AN000; + CALL PRINT_STDOUT ;show message "Already Installed" + stc + +Install_Exit: + pop bp ;restore registers + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret ;return + +INSTALL_FASTOPEN ENDP + + + + + + +;---------------------------------------------------------------------------- +; CHECK_MEM +;---------------------------------------------------------------------------- +; Function: Compute the total size of memory required by the Fasteopen. +; This includes both code and the cache buffers. +; +; Input: Name_Count, extent_count, Drive_cache, num_of_drives +; +; Output: Memory is validated, Resident segment size is calculated +; Temporary stack segment is set +;---------------------------------------------------------------------------- +CHECK_MEM PROC NEAR ; DS-->Cseg_init + +;** Compute the total resident segment size and then add the cache buffer +;** size. The Resident segment size should be adjusted again after relocation. + + mov Total_Cache_Size,0 ;reset total cache size (Name +Ext) + mov Name_Cache_Size,0 ;reset Name cache buffer size + mov ax, offset End_Main ;size of Main_Seg in bytes ;AN000; + add ax,15 ;AN000; + mov cl,4 ;convert size to paragraph ;AN000; + shr ax,cl ;by dividng by 16 ;AN000; + mov MAIN_Size, ax ;save MAIN segment size in para ;AN000; + add Res_Segs,ax ;update resident seg count ;AN000; + ;AN000; + mov ax, offset End_Open ;size of Open_Seg in bytes ;AN000; + add ax,15 ;AN000; + mov cl,4 ;convert it to paragraph ;AN000; + shr ax,cl ;AN000; + mov OPEN_Size, ax ;save OPEN segment size in para ;AN000; + add RES_SEGS,ax ;update resident seg count ;AN000; + ;AN000; + mov ax, offset End_Seek ;add size of Seek_Seg + add ax,15 ;AN000; + mov cl,4 ;AN000; + shr ax,cl ; convert to para (divide by 16) ;AN000; + mov SEEK_Size, ax ;save Seek segment size in para ;AN000; + add RES_SEGS,ax ;update resident seg count ;AN000; + +;---------------------------------------------------------------------------- +; Calculate the size of the NAME DRIVE HEADER BUFFERS +;---------------------------------------------------------------------------- + xor ax,ax ;reset the cache size register + cmp total_Name_Count,0 ;Fastopen enabled ?? + je Check_ext_cache ;no - compute extent cache size + + mov bx,offset DRIVE_CACHE ;get beginning of cache buff + xor ax,ax + mov al,size drive_cache_header ;get size of one name entry + mul Num_Of_drives ;get total needed for drive cache + add ax,bx ;set up correct offset + add ax,15 ;round up to paragraph boundary + mov cl,4 + shr ax,cl ;convert to paragraphs + add RES_SEGS,ax ;update resident seg count + mov Total_Cache_Size, ax ;update total cache buff size + mov Name_Cache_Size, ax ;size in paragraph + +; Calculate the offset of the Name cache buffers + shl ax,cl ;AX = offset to Name cache buff + mov NAME_CACHE_BUFF,ax ;save Name cache address + +;----------------------------------------------------------------------------- +; Compute the size of the NAME CACHE buffer +;----------------------------------------------------------------------------- + mov ax,size Name_Record + mul Total_Name_Count + add ax,15 ;round up to paragraph boundary + mov cl,4 + shr ax,cl ;convert to paragraphs ( divide 16) + add RES_SEGS,ax ;AX = End of Name cache buffers + add Total_Cache_Size,ax ;update total cache buff size + add Name_Cache_Size, ax ; + +Check_Ext_Cache: + cmp total_ext_count,0 ;Fastseek enabled ?? + je Set_Stack ;no, set stack + +;--------------------------------------------------------------------------- +; Compute the size of the Extent cache including drive headers +;--------------------------------------------------------------------------- +Compute_Ext_Cache: ;calculate the extent buff offset + mov ax,Name_Cache_Size + mov cl,4 + shl ax,cl ;convert to bytes ( multiply by 16) ;AN000; + mov EXTENT_DRIVE_BUFF, ax ;save EXTENT DRIVE BUFFER address ;AN000; + + mov ax, size Drive_Header ;AN000; + mul num_Of_drives ;calc size of drive header buff ;AN000; + mov bx,ax ;save AX in BX ;AN000; + mov ax, size Extent_Header ;size of one extent ;AN000; + mul Total_Ext_Count ;calc size of extent buffers ;AN000; + add ax,bx ;AX = size of extent buff in bytes ;AN000; + mov ext_cache_size,ax ;save it for later use ;AN000; + add ax,15 ;round up to paragraph boundary ;AN000; + mov cl,4 ;AN000; + shr ax,cl ;convert to paragraphs ;AN000; + add RES_SEGS,ax ;update resident seg count ;AN000; + add Total_Cache_Size,ax ;update total cache buff size + + +;---------------------------------------------------------------------------- +; Setup stack segment followed by the extent cache buffers. This is a +; temporary stack used by the drive buffer initilization code in the +; Cseg_Main segment. This stack will be overlayed by the cache buffers. +;---------------------------------------------------------------------------- +Set_Stack: + mov ax,RES_SEGS ;AX=size of code and buffs in para + add ax,PSP_Seg ;AX=segID of stack + mov Stack_Seg_Start,ax ;start of the new STACK + add ax,20h ;add the size of the stack + mov Stack_Seg_End,ax ;get end of what we need + + push ds ; + mov ds,PSP_Seg ;access PSP for memory size + mov si,Top_mem + LODSW ;get total memory size + pop ds + sub ax,Stack_Seg_End ;see if there is enough for us + jc Not_Enough_Memory ;no - error exit + sub ax,1000h ;will there still be 64K ?? + jnc Check_Reloc_Size ;and return + +Not_Enough_Memory: + MOV AX,NOT_ENOUGH_MEM ;message number ;AN000; + MOV MSG_NUM,AX ;set message number ;AN000; + MOV SUBST_COUNT,0 ;no message substitution ;AN000; + MOV MSG_CLASS,-1 ;message class ;AN000; + MOV INPUT_FLAG,0 ;no input ;AN000; + CALL PRINT_STDOUT ;show message "Insufficient Memory" ;AN000; + stc ;set error flag ;AN000; + jmp short Set_Mem_Ret ;return ;AN000; + +;------------------------------------------------------------------------------ +; If relocation is needed, then recalculate the size of resident segment +; If extended memory relocation, OPEN, SEEK and INIT segments will be +; eliminated from the current resident seg. +;----------------------------------------------------------------------------- +Check_Reloc_Size: + cmp Ext_Mem,1 ; extended memory relocation ?? + jne Set_Mem_Exit ; no - exit ;AN000; + +;----------------------------------------------------------------------------- +; Check to see that the both code and the cache buffers fit in the +; exteneded memory one 16K page. Since the entire code segment and the +; cache buffers are going to be moved to XMA, that amount should be +; reduced from the size that should reside in the low memory. +;----------------------------------------------------------------------------- + xor ax,ax + xor bx,bx + cmp total_Name_Count,0 ;Fastseek enabled ?? + je Skip_name_size ;no - skip name size + mov ax, OPEN_SIZE ;size of Open seg in para ;AN000; +Skip_Name_Size: + cmp total_ext_count,0 ;Fastseek enabled ?? + je Skip_Ext_Size ;no - skip extent size + mov bx, SEEK_Size ;size of Seek_Seg in para ;AN000; +Skip_Ext_Size: + add ax,bx + add ax, Total_Cache_Size ;size of Init_Seg in para ;AN000; + cmp ax, 0404H ;Less than 16K ?? ;AN000; + jge Not_Enough_Space ;no - display message ;AN000; + + mov ax, OPEN_SIZE ;size of Open seg in para ;AN000; + add ax, SEEK_Size ;size of Seek_Seg in para ;AN000; + add ax, Total_Cache_Size ;reduce resident seg size ;AN000; + sub RES_SEGS,ax ;update resident seg count ;AN000; + +;----------------------------------------------------------------------------- +; If the code is to be moved to extended memory. There is no reason to +; keep Init_Tree in main memory. Remove that also to save space in base memory +;----------------------------------------------------------------------------- + mov ax, offset End_Main1 ;size of Main_Seg until Init_Tree (bytes) ;AN000; + add ax,15 ;AN000; + mov cl,4 ;convert size to paragraph ;AN000; + shr ax,cl ;by dividng by 16 ;AN000; + mov bx,Main_Size ;bx=total size of Main seg including Init_Tree + sub bx,ax ;bx=size after reducing Init_Tree + sub RES_SEGS,bx ;update base memory resident seg count ;AN000; + jmp short Set_Mem_Exit + ; +Not_Enough_Space: + MOV AX,NO_PAGE_SPACE ; not enough space in EMS page + MOV MSG_NUM,AX ; set message number + MOV SUBST_COUNT,0 ; no message + MOV MSG_CLASS,-1 ; message class + MOV INPUT_FLAG,0 ; no input + CALL PRINT_STDOUT ; display message + mov Ext_Mem, 0 ; RESET XMA FLAG + stc + jmp set_mem_ret + +Set_Mem_Exit: ;AN000; + clc ;AN000; + +Set_Mem_Ret: + ret ;AN000; + +CHECK_MEM endp + + + + + +;---------------------------------------------------------------------------- +; RELOCATE +;---------------------------------------------------------------------------- +; Function: Relocate Fastopen code and buffer in base memory or in +; Extended Memory. If base memory relocation, then +; relocate Cseg_Seek over Cseg_Open segment if the user +; didn't specify Fastopen (n). Relocate Cseg_Init over Cseg_Seek +; if user didn't specify Fastseek feature(m). If extended memory +; relocation, copy Cseg_Open, Cseg_Seek and Cseg_Init to +; a single page in extented memory if both Fastopen and Fastseek +; (n and m) are specified. Copy Cseg_open and Cseg_Init only if Fastseek +; feature (m) is not specified. Copy Cseg_Seek and Cseg_Init if +; FastOpen feature (n) is not specified +; +;---------------------------------------------------------------------------- + +RELOCATE_SEGMENT PROC NEAR + cmp Ext_Mem,1 ; Extended memory enabled ?? ;AN000; + je Set_Seg_Ids ; yes - do extented memory relocation + jmp Reloc_Low_Mem ; no - do low memory relocation ;AN000; + +;---------------------------------------------------------------------------- +; Move Fastopen, FastSeek or both to the Extended memory +;---------------------------------------------------------------------------- +Set_Seg_Ids: + cld ; clear direction flag (increment si and di) + cmp Total_Name_Count,0 ; Fastopen enabled ?? + jne Set_Open_Seg ; yes - set open seg in extented memory + + mov ax,EMS_Page_Seg ; AX = seg id of Cseg_Seek in ext mem + mov Seek_SegID,ax ; save it + jmp Set_Seek_Seg ; no - fastopen, set Seek segment + +;----------------------------------------------------------------------------- +; ---- Extended Memory Relocation ----- +; Setup Cseg_Open segment in Extended Memory +;------------------------------------------------------------------------------ +Set_Open_Seg: + mov ax,Cseg_Init ; + mov ds,ax ; DS-->Cseg_Init + ASSUME ds:Cseg_Init + mov ax,EMS_Page_Seg ; AX = seg id of Cseg_Open in ext mem + mov Open_SegID,ax ; save it + +Copy_Open_Seg: + mov ax, offset End_Open ; size of Open seg in bytes ;AN000; + mov cl,1 + shr ax,cl ; convert to words ;AN000; + mov cx,ax ; CX = number of WORDS to transfer ;AN000; + xor si,si ; offset of the source in low memory ;AN000; + xor di,di ; offset of the destination in XMA ;AN000; + mov ax,Cseg_Open ; set source segID ;AN000; + mov ds,ax ; DS-->Cseg_Open ;AN000; + ASSUME ds:Cseg_Open ;AN000; + mov ax,Open_SegID ; set destination XMA seg id ;AN000; + mov es,ax ; ES-->Extended memory page ;AN000; + ASSUME es:nothing ;AN000; + REP MOVSW ; copy Open segment to extended memory + ; SI-->Cseg_Seek segment + mov ax,Cseg_Init ; no - only Fastseek specified + mov ds,ax ; DS-->Cseg_Init + ASSUME ds:Cseg_Init + cmp Total_Ext_Count,0 ; Fastseek enabled ?? + jne Set_Seek_id ; yes -set seek id + + mov ax,Cseg_Seek ; only Fastopen is enabled ;AN000; + sub ax,Cseg_Open ; AX = size of Cesg_Open segment ;AN000; + add ax,EMS_Page_Seg ; AX = new seg ID of Cseg_Init in ext ;AN000; + mov Init_SegID,ax ; only if Fastopen is specified ;AN000; + jmp Copy_Init_Seg ; copy init_seg to extended memory + +;----------------------------------------------------------------------------- +; Setup Cseg_Seek segment in Extended Memory +;------------------------------------------------------------------------------ +Set_Seek_Id: + mov ax,Cseg_Seek ; + sub ax,Cseg_Open ; AX = size of Cesg_Open segment ;AN000; + add ax,EMS_Page_Seg ; AX = new seg ID of Cseg_Seek in ;AN000; + mov Seek_SegID,ax ; extended memory ;AN000; + jmp Copy_Seek_Seg + +Set_Seek_Seg: ; only Fastseek is specified + xor si,si ; offset of the source in low memory ;AN000; + xor di,di ; offset of the destination in XMA ;AN000; + +Copy_Seek_Seg: + mov ax, offset End_Seek ;size of Cseg_Seek in bytes ;AN000; + mov cl,1 + shr ax,cl ; convert to words ;AN000; + mov cx,ax ; CX = number of WORDS to transfer ;AN000; + xor si,si ; offset of the source in low memory ;AN000; + xor di,di ; offset of the destination in XMA ;AN000; + mov ax,Cseg_Seek ; set source segID ;AN000; + mov ds,ax + ASSUME ds:Cseg_Seek ;AN000; + mov ax,Seek_SegID ; set destination XMA seg id ;AN000; + mov es,ax + ASSUME es:nothing ;AN000; + REP MOVSW ; copy Seek segment to extended memory + ; SI-->Cseg_Init segment + mov ax,Cseg_Init ; no - only Fastseek specified + mov ds,ax ; DS-->Cseg_Init + ASSUME ds:Cseg_Init + cmp total_Name_Count,0 ; FastOpen enabled ?? + jne Set_Init_Seg ; yes - set Init Segment + + mov ax,Cseg_Init + sub ax,Cseg_Seek ; ax = size of Cseg_Seek + add ax,EMS_Page_Seg ; Cseg_Init id only if Fastseek is specified + mov Init_SegID,ax ; + jmp copy_init_seg ; copy cseg_init area to extentde memory + +;----------------------------------------------------------------------------- +; Setup Cseg_Init segment in Extended Memory +;------------------------------------------------------------------------------ +Set_Init_seg: + mov ax,Cseg_Init ; yes - set init seg id + sub ax,Cseg_Open ; AX = size of Open_Cseg+Seek_Cseg + add ax,EMS_Page_Seg ; new Cseg_Init id in XMA if both + mov Init_SegID,ax ; Fastopen and Fastseek are enabled ;AN000; + +Copy_Init_Seg: ; comes here if no Cseg_Seek is required + xor si,si ; offset of the source in low memory ;AN000; + xor di,di ; offset of the destination in XMA ;AN000; + mov ax, Total_Cache_Size ; size of Init seg area to be copied ;AN000; + mov cl,4 ; in paragraph ;AN000; + shl ax,cl ; convert to number of bytes ;AN000; + mov cl,1 ; + shr ax,cl ; convert to number ofwords ;AN000; + mov cx,ax ; CX = number of WORDS to transfer ;AN000; + mov ax,Cseg_Init ; set source segID ;AN000; + mov ds,ax + ASSUME ds:Cseg_Init ;AN000; + mov ax,Init_SegID ; set destination XMA seg id ;AN000; + mov es,ax + ASSUME es:nothing ;AN000; + REP MOVSW ; copy Init segment to extended memory + jmp reloc_exit ; then return ;AN000; + + +;NOTE: No need to adjust the resident segment size (Res_Segs) since it is +; done in the routine (Check_Mem). + + +;----------------------------------------------------------------------- +; ---- LOW MEMORY RELOCATION ---- +; Reloctae FastOpen or FastSeek or both in the low memory and adjust the +; resident size of the code. +;----------------------------------------------------------------------- +Reloc_LOW_Mem: + cmp Total_Name_Count,0 ; Fastopen function enabled ?? + jne Check_Seek ; yes, check Fastseek function + +; Relocate Cseg_Seek segment over Cseg_Open segment + mov ax, offset End_Seek ; size of Cseg_Seek in bytes ;AN000; + mov cl,1 + shr ax,cl ; convert to words ;AN000; + mov cx,ax ; CX = number of WORDS to transfer ;AN000; + xor si,si ; offset of the source ;AN000; + xor di,di ; offset of the destination ;AN000;;AN000; + mov ax,Cseg_Seek ; set source segID ;AN000; + mov ds,ax ; DS:SI-->Cseg_Seek ;AN000; + ASSUME ds:Cseg_Seek ;AN000; + mov ax,Cseg_Open ; set destination seg id ;AN000; + mov es,ax ; ES:DI--> Cseg_Open ;AN000; + ASSUME es:Cseg_Open ;AN000; + ;AN000; + REP MOVSW ; relocate code and cache buffer + mov ax,OPEN_Size ; reduce Open seg size from + sub RES_SEGS,ax ; the resident size + +;----------------------------------------------------------------------- +; Compute the new segID after relocation and save it +;----------------------------------------------------------------------- + mov ax,Cseg_Init ; + mov ds,ax ; DS-->Cseg_Init + ASSUME ds:Cseg_Init + mov ax,Cseg_Open ; AX = seg id of Cseg_Open in ext mem + mov Seek_SegID,ax ; save it + ;AN000; + mov ax,Seek_Size ; AX = size of Cseg_Seek + add ax,Cseg_Open ; AX = new seg ID of Cseg_Init in ext ;AN000; + mov Init_SegID,ax ; save it ;AN000; + jmp short reloc_exit ;then return ;AN000; + +Check_Seek: + cmp Total_Ext_Count,0 ; Fastseek function enabled ?? + jne Reloc_Exit ; yes, no need for relocation + +;----------------------------------------------------------------------- +; Relocate first portion of the Cseg_Init over Cseg_Seek segment. The size +; this portion should be same as the current size of Drive cache headers +; Anything more will overlay on Cseg_Init code which is currently active. +;----------------------------------------------------------------------- + mov ax, size Drive_Cache_Header ; size of one drive cache hdr + mov cx,Max_Drives ; CX = maximum number of drives + mul cx ; AX = size of Cseg_Init portion + mov cl,1 + shr ax,cl ; AX = size of portion in words + mov cx,ax ; CX = number of WORDS to transfer ;AN000; + mov si,0 ; offset of the source ;AN000; + mov di,0 ; offset of the destination ;AN000;;AN000; + mov ax,Cseg_Init ; set source segID ;AN000; + mov ds,ax ; DS:SI-->Cseg_Seek ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov ax,Cseg_Seek ; set destination seg id ;AN000; + mov es,ax ; ES:DI--> Cseg_Open ;AN000; + ASSUME es:Cseg_Seek ;AN000; + ;AN000; + REP MOVSW ; relocate Cseg_Init over Cseg_Seek + mov ax,Seek_Size ; reduce Seek seg size from + sub RES_SEGS,ax ; the resident size + +;----------------------------------------------------------------------- +; Compute the new segID after reloaction and save it +;----------------------------------------------------------------------- + mov ax,Cseg_Init ; + mov ds,ax ; DS-->Cseg_Init + ASSUME ds:Cseg_Init + mov ax,Cseg_Seek ; AX = seg id of Cseg_Open in ext mem + mov Init_SegID,ax + +Reloc_Exit: +; copy the latest RES_SEGS size to Cseg_Main + mov ax,Cseg_Init ; ;AN000; + mov ds,ax ; DS-->Cseg_Init ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov ax,Cseg_Main ; set destination seg id ;AN000;;AN000; + mov es,ax ; ES--> Cseg_Main ;AN000; ;AN000; + ASSUME es:Cseg_Main ;AN000;;AN000; + mov ax,Res_Segs ;AN000; + mov es:Main_Res_Segs,ax ; save it ;AN000; + + RET ;AN000; + +RELOCATE_SEGMENT ENDP + + + + + + +;----------------------------------------------------------------------- +; Procedure: COPY_DATA +;----------------------------------------------------------------------- +; Copy data values from Cseg_Init to other segments. I the code is relocated, +; seg IDs should be updated after relocation. This is done in "Update_SegID" +; +; Input: Variables inside Cseg_Open, CsegSeek and Cseg_Main segments +; +; Output: Data values copied to the above segments +; +; +;----------------------------------------------------------------------- + +COPY_DATA PROC NEAR + + mov ax,cseg_init ;AN000; + mov ds,ax ;DS--> Cseg_Init ;AN000; + ASSUME ds:Cseg_init ;AN000; + mov ax,cseg_Main ;AN000; + mov es,ax ;ES--> CSEG_MAIN ;AN000; + ASSUME es:Cseg_Main ;AN000; + ;AN000; + mov es:Main_Name_Cache_Seg, Cseg_Init ;AN000; + mov ax,Num_Of_Drives ;AN000; + mov es:Main_Num_Of_Drives,ax ;AN000; + mov ax,ext_count ;AN000; + mov es:Main_Ext_Count,ax ;AN000; + mov ax,Extent_Drive_Buff ;AN000; + mov es:Main_Extent_Drive_Buff,ax ;AN000; + mov ax,Name_Cache_Buff ;AN000; + mov es:Main_Name_Cache_Buff,ax ;AN000; + mov ax,Name_Drive_Buff ;AN000; + mov es:Main_Name_Drive_Buff,ax ;AN000; + mov ax,Ems_Flag + mov es:Main_EMS_FLAG,ax + mov ax,EMS_PAGE_Seg ;AN000; + mov es:Main_EMS_PAGE_Seg,ax ;AN000; + +IF BUFFERFLAG + mov ax, EMS_PAGE_NUM + mov es:ems_page_number, ax ;HKN +ENDIF + + mov ax,EMS_PAGE_SIZE ;AN000; + mov es:Main_EMS_PAGE_SIZE,ax ;AN000; + mov ax,Total_Ext_Count ;AN000; + mov es:Main_Total_Ext_Count,ax ;AN000; + mov ax,Ext_Cache_Size ;AN000; + mov es:Main_Ext_Cache_Size,ax ;AN000; + mov ax,Total_Name_Count ;AN000; + mov es:Main_Total_Name_Count,ax + +; Copy drive buffer to MAIN segment + lea si,ParamBuff ;AN000; + lea di,es:Main_ParamBuff ;AN000; + mov cx,50 ;AN000; + +Paramloop: + mov al,[si] ;AN000; + mov es:[di],al ;AN000; + inc si ;AN000; + inc di ;AN000; + LOOP paramloop ;AN000; + +;----------------------------------------------------------------------- +; Copy data values to OPEN segment (Cseg_Open) +;----------------------------------------------------------------------- + mov ax,cseg_Open ;AN000; + mov es,ax ;ES--> CSEG_Open ;AN000; + ASSUME es:Cseg_Open ;AN000; + mov si,offset drive_cache ;AN000; + mov es:Open_Name_Drive_Buff,si ;AN000; + mov es:Open_Name_Cache_Seg,Cseg_Init ;AN000; + mov ax,check_Queue + mov es:chk_Flag,ax + +;----------------------------------------------------------------------- +; Copy data values to SEEK segment (Cseg_Seek) for Fastseek functions +;----------------------------------------------------------------------- + mov ax,cseg_Seek ;AN000; + mov es,ax ;ES--> CSEG_Seek ;AN000; + ASSUME es:Cseg_Seek ;AN000; + mov si,Extent_Drive_Buff ;AN000; + mov es:Seek_Extent_Drive_Buff,si ;AN000; + mov es:Seek_Name_Cache_Seg,Cseg_Init ;AN000; + mov ax,Num_Of_Drives ;AN000; + mov es:Seek_Num_Of_Drives,ax ;AN000; + mov ax,Total_Ext_Count ;AN000; + mov es:Seek_Total_Ext_Count,ax ;AN000; + mov ax,Total_Name_Count ;AN000; + mov es:Seek_Total_name_Count,ax ;AN000; + mov ax,Name_Cache_Buff ;AN000; + mov es:Seek_Name_Cache_Buff,ax ;AN000; + mov ax,Name_Drive_Buff ;AN000; + mov es:Seek_Name_Drive_Buff,ax ;AN000; + mov ax,check_Queue + mov es:check_Flag,ax + ;AN000; + mov ax,cseg_Init ;AN000; + mov es,ax ;ES addressability to CSEG_Init ;AN000; + ASSUME es:Cseg_Init ;AN000; + ;AN000; + ret + +COPY_DATA ENDP + + + + +;----------------------------------------------------------------------- +; Procedure: ADJUST_SEGIDS +;----------------------------------------------------------------------- +; Function: Adjust segment Ids of various segments after relocation +; +; Input: SegID Vectors +; +; Output: SegIDs vectors are adjusted +; +; Note: The following segid and vectors are set previously either during +; link time or during initialization time. These SegIDS needs to +; be changed after the code and buffers are relocated. +;----------------------------------------------------------------------- + +ADJUST_SEGIDS PROC NEAR + + mov ax,Cseg_Init ;AN000; + mov ds,ax ;DS addressability to Cseg_Init ;AN000; + ASSUME ds:Cseg_init ;AN000;;AN000; + mov ax,cseg_Main ;AN000; + mov es,ax ;ES addressability to CSEG_MAIN ;AN000; + ASSUME es:Cseg_Main ;AN000; + + mov bx, Init_segID ; copy seg ID of Init_Seg to ;AN000; + mov es:Main_Name_Cache_Seg, bx ; Main seg ;AN000; + + cmp Total_Name_Count,0 ; Fastopen function enabled ?? + je Adjust_Seek ; yes, Adjust Cseg_Seek ID + + mov ax,Open_SegID ;AN000; + mov es,ax ; ES addressability to CSEG_Open ;AN000; + ASSUME es:Cseg_Open ; copy segid of init_seg to ;AN000; + mov es:Open_Name_Cache_Seg, bx ; Open segment + +Adjust_Seek: + cmp Total_Ext_Count,0 ;Fastopen function enabled ?? + je Adjust_Vectors ;yes, check Fastseek function + + mov ax,Seek_SegID ;AN000; + mov es,ax ; ES addressability to CSEG_Seek ;AN000; + ASSUME es:Cseg_Seek ;AN000; + mov es:Seek_Name_Cache_Seg, bx ;AN000; + + +; Adjust seg ids of jump vectors to Fastopen and Fastseek functions ;AN000; +Adjust_Vectors: + mov ax,cseg_Main ;AN000; + mov es,ax ;ES addressability to CSEG_MAIN ;AN000; + ASSUME es:Cseg_Main ;AN000; + ;DS addressability to Cseg_Init + mov ax, Open_SegID ;AN000; + mov word ptr es:FOPEN_Insert + word, ax ;AN000; + mov word ptr es:FOPEN_Update + word, ax ;AN000; + mov word ptr es:FOPEN_Delete + word, ax ;AN000; + mov word ptr es:FOPEN_Lookup + word, ax ;AN000; +IF BUFFERFLAG + mov word ptr es:FOPEN_Purge + word, ax ;TEL 9/29 +ENDIF + + + mov ax, Seek_SegID ;AN000; + mov word ptr es:FSEEK_Open + word, ax ;AN000; + mov word ptr es:FSEEK_Close + word, ax ;AN000; + mov word ptr es:FSEEK_Insert + word, ax ;AN000; + mov word ptr es:FSEEK_Delete + word, ax ;AN000; + mov word ptr es:FSEEK_Lookup + word, ax ;AN000; + mov word ptr es:FSEEK_Truncate + word, ax ;AN000; + mov word ptr es:FSEEK_Purge + word, ax ;AN000; + + cmp Total_Name_Count,0 ; Fastopen function enabled ?? + je Adjust_Delete ; no , exit + +; Change the segID of single Jump Vector inside Cseg_Main + mov ax,cseg_Main ;AN000;;AN000; + mov es,ax ;ES addressability to CSEG_MAIN ;AN000;;AN000; + ASSUME es:Cseg_Main ;AN000;;AN000; + mov ax,Open_SegID ;AN000; + mov word ptr es:Vector_LookUp + word, ax ;;AN000;AN000; + +Adjust_Delete: + cmp Total_Ext_Count,0 ; Fastseek function enabled ?? + je Adjust_Exit ; no , exit + +; Change the segID of single Jump Vector inside Cseg_Main + mov ax,cseg_Main ;AN000;;AN000; + mov es,ax ;ES addressability to CSEG_MAIN ;AN000;;AN000; + ASSUME es:Cseg_Main ;AN000;;AN000; + mov ax,Seek_SegID ;AN000; + mov word ptr es:Vector_Delete + word, ax ;;AN000;AN000; + +Adjust_Exit: + ret ;AN000; + ;return +ADJUST_SEGIDS ENDP + + + + + + + + +;****************************************************************************** +; * +; * MODULE: PARSE +; * +; * FUNCTION: Parse command line +; * +; * INPUT: FASTOPEN d: {=n | (n,m) } ... /x à +; * where à activates queue analyser for debugging +; * +; * OUTPUT: Command line is parsed +; * +; * RETURN SEQUENCE: +; * +; * If CY = 0 No error +; * +; * If CY = 1 Error +; * +; * EXTERNAL REFERENCES: SYSPARSE +; * +; ************************************************************************* + +EOL EQU -1 ; Indicator for End-Of-Line +NOERROR EQU 0 ; Return Indicator for No Errors + + +PARSE PROC NEAR + + mov num_of_drives,0 ; initialize drive count + mov name_count,0 + mov ext_count,0 + mov Total_name_count,0 ;AN000; + mov Total_ext_count,0 ;AN000; + mov Prev_Type,0 ;AN000; + mov Ext_Mem,0 ;AN000; + mov Check_Queue,0 ;AN000; + lea si,parambuff ; drive ID buff address ;AN000; + mov parmbuff_Ptr,si ; save it ;AN000; + +;---------------------------------------------------------------------------- +; Get command string address from PSP +;---------------------------------------------------------------------------- + mov si,0081H + mov ah,62H + INT 21H ; get program PSP segment ;AN000; + mov PSP_Seg,bx ; save PSP segment ;AN000; + ;AN000; + mov ds,bx ; DS = PSP segment ;AN000; + mov si,0081h ; SI-->beginning of parameter string in PSP + lea di,cmdline_buff ; DI-->command param buffer ;AN000; + mov cx,127 ; copy 127 bytes from PSP ;AN000; + +;---------------------------------------------------------------------------- +; Copy command parameters from PSP to the command buffer +;---------------------------------------------------------------------------- +Cmdloop: + mov al,ds:[si] ; DS:SI-->Command line ;AN000; + mov es:[di],al ; ES:DI-->program command buffer ;AN000; + inc si ;AN000; + inc di ;AN000; + LOOP cmdloop ; copy command line + push cs ;AN000; + pop ds ;AN000; + +;---------------------------------------------------------------------------- +; set parametrs for SysParse call +;---------------------------------------------------------------------------- + xor cx,cx ; no params processed so far ;AN000; + MOV ORDINAL,CX ; SAVE initial ordinal value ;AN000; + lea si,cmdline_buff ; ES:SI-->command line ;AN000; + lea di,parms ; ES:DI-->parameter + MOV CURRENT_PARM,SI ; pointer to next positional ;AN000; + + mov ax,0100h ; Drive only + mov pos1type,ax ; set positional control block 1 ;AN000; + mov ax,08502h ; Numeric/Complex/Drive/Repeat + mov pos2type,ax ; set positional control block 2 ;AN000; + mov al,1 ; minimum 1 positional ;AN000; + mov Par_Min,al ; + mov al,2 ;AN000; + mov Par_Max,al ; maximum 1 positional ;AN000; + jmp short set_param + +;---------------------------------------------------------------------------- +; MAIN PARSE LOOP +;---------------------------------------------------------------------------- +PARSE_LOOP: ; MAIN PARSE LOOP + mov ax,08502h ; number/drive ID/comlex/repeat + mov pos1type,ax ; set positional control block ;AN000; + mov ax,08502h ; + mov pos2type,ax ; + mov al,1 ; minimum 1 positional ;AN000; + mov Par_Min,al ; set min + mov al,2 ; maximum 2 positionals ;AN000; + mov Par_Max,al ; set max ;AN000; + +Set_Param: + mov Par_sw,1 ; set switch flag in PARSMX + xor dx,dx + push cs ;AN000; + pop es ; ES=DS=CS ;AN000; + LEA DI,PARMS ; ES:DI = PARSE CONTROL DEFINITON ;AN000; + MOV SI,CURRENT_PARM ; DS:SI = next positional ;AN000; + XOR DX,DX ; RESERVED, INIT TO ZERO ;AN000; + MOV CX,ORDINAL ; OPERAND ORDINAL, INITIALLY ;AN000; + + CALL SYSPARSE ; Parse current positional + + mov Next_Parm,si ; save pointer to next positional ;AN000; + mov ORDINAL,CX ; save current ordinal ;AN000; + cmp ax,EOL ; END-OF-COMMAND string ?? ;AN000; + jne Parse_chk_Error ; no - check error + + +;---------------------------------------------------------------------------- +; If previous positional is a drive ID without Name or Extent count then assign +; default counts . +;---------------------------------------------------------------------------- + cmp Prev_Type,6 ; previous param = drive ID ;AN000; + jne Take_Exit ; no - exit ;AN000; + ;AN000; + CALL PROC_DEFAULT ; yes - setup default counts for previous drive ;AN000; + jnc Take_Exit ; exit ;AN000; + jmp parse_Error ; error exit ;AN000; + +Take_Exit: + CALL Verify_Counts ; verify the Total counts + jnc Counts_OK ; exit if count ok + jmp parse_error ; else error exit + +Counts_Ok: + jmp parse_exit ; normal - exit + + +;---------------------------------------------------------------------------- +; CHECK ERROR CONDITIONS +;---------------------------------------------------------------------------- +Parse_Chk_Error: ; check for error conditions + cmp ax,NOERROR ; any parse error ?? + jne verify_missing_oper ; yes - check missing operand + jmp Chk_Result ; no - check result buffer ;AN000; + +Verify_Missing_Oper: + cmp ax,2 ; yes - missing operand error?? + jne disp_error ; no - jump ;AN000; + + cmp Prev_Type,0 ; yes - any previous parameters ?? + jne Chk_Prev_Drive ; yes, previous drive id ;AN000; + mov MSG_CLASS,2 + MOV MSG_NUM,AX ; set message number ;AN000; + MOV SUBST_COUNT,0 ; no message substitution ;AN000; + MOV INPUT_FLAG,0 ; no input ;AN000; + CALL PRINT_STDOUT ; show message ;AN000; + stc ; set error flag ;AN000; + jmp Parse_Exit ; exit + +;---------------------------------------------------------------------------- +; If previous positional is drive ID without counts then assign default counts +;---------------------------------------------------------------------------- +Chk_prev_drive: + cmp Prev_Type,6 ; previous param = drive ID ?? ;AN000; + jne Take_Exit1 ; no - exit ;AN000; + + CALL PROC_DEFAULT ; yes - assign default ID + jnc Take_Exit1 ; no error, verify counts ;AN000; + jmp parse_Error ; error exit ;AN000; + +Take_Exit1: + CALL Verify_Counts ; verify the Total counts + jnc Counts_right ; count ok - check special case + jmp parse_error ; error - exit + +Counts_right: + cmp Prev_Type,0 ; no previous param ? (Special case) ;AN000; + je invalid_operand ; no, exit ( FASTOPEN >TEMP ) case ;AN000; + clc ;AN000; + jmp parse_exit ; exit + +Invalid_Operand: ; else error + jmp bad_param + +Disp_Error: + cmp ax, 3 ; invalid switch type ?? + jne bad_param ; no - + jmp Bad_Switch + +;---------------------------------------------------------------------------- +; If user entered à to activate the analyser, than verify the previous +; drive case. If true, assign default name extent entries, set activation +; flag and take normal exit. +;---------------------------------------------------------------------------- +Bad_Param: + mov si,Current_Parm ; SI-->current parameter (analyser hook) + mov al,0e0h ; à (hidden character to activate analyser) + cmp [si],al ; activate analyser ?? + jne set_disp_param ; no - normal error + mov Check_Queue,1 ; yes - set flag to activate analyser + clc + jmp Chk_Prev_Drive ; exit + +Set_Disp_Param: + mov di,Next_Parm ; ending address of bad param (1/6/88) + mov al,0 + mov ds:[di],al ; set termination character + LEA SI,SUBLIST1 ; DS:SI-->Substitution list ;AN000; + MOV AX,CURRENT_PARM ; starting address of bad parameter ;AN000; + MOV [SI].DATA_OFF,AX ; SI-->File name ;AN000; + MOV [SI].DATA_SEG,DS ; DS-->Segment ;AN000; + MOV [SI].MSG_ID,0 ; message ID ;AN000; + MOV [SI].FLAGS,010H ; ASCIIZ string, left align ;AN000; + MOV [SI].MAX_WIDTH,0 ; MAXIMUM FIELD WITH ;AN000; + MOV [SI].MIN_WIDTH,0 ; MINIMUM FIELD WITH ;AN000; + mov ax,incorrect_param ; Error Code ;AN000; + MOV MSG_NUM,AX ; set message number ;AN000; + MOV SUBST_COUNT,1 ; substitution count ;AN000; + MOV MSG_CLASS,-1 ; message class ;AN000; + MOV INPUT_FLAG,0 ; no input ;AN000; + CALL PRINT_STDOUT ; display message ;AN000; + stc ; error flag + jmp Parse_Exit ; exit (1/6/88 P2670) + + +;---------------------------------------------------------------------------- +; CHECK POSITIONAL PARAMETER TYPE +;---------------------------------------------------------------------------- +Chk_Result: + push es ; get DS back to Program data segment ;AN000; + pop ds ;AN000; + cmp postype,1 ; number ?? ;AN000; + jne chk_switch ;AN000; + jmp short Proc_Name ; yes, process name entry ;AN000; + +chk_switch: + cmp postype,3 ; switch ?? ;AN000; + je Proc_sw ; yes, process switch ;AN000; + cmp postype,6 ; drive id ?? ;AN000; + je Proc_driveid ; yes, Process Drive ID ;AN000; + cmp postype,4 ; complex item ?? ;AN000; + jne disp_msg ;AN000; + jmp Proc_complex ; yes, process Complex item ;AN000; + +disp_msg: + mov ax,incorrect_param ; no, check reult buffer ;AN000; + jmp bad_param ; else error ;AN000; + +Proc_Sw: jmp Proc_Switch ; process switch ;AN000; + + + +;---------------------------------------------------------------------------- +; PROCESS DRIVE ID +;---------------------------------------------------------------------------- +PROC_DRIVEID: ; PROCESS DRIVE ID + cmp Prev_Type,6 ; previous param = drive ID ;AN000; + jne check_drive_id ; no, jump ;AN000; + ;AN000; +; if not set default name and extent entry count for previous drive + CALL PROC_DEFAULT ; setup default counts ;AN000; + jnc Check_Drive_id ; ;AN000; + jmp parse_Error ;AN000; + +Check_Drive_Id: ; process current drive ID + mov ax,ValueLo ; get drive letter number from result buff ;AN000; + ; C:=3 D:=4 etc, Parser drive id convention ;AN000; + add al,040H ; convert to drive letter ;AN000; + + CALL CHECK_DRIVE ; validate drive ID ?? ;AN000; + jnc set_drive_id ; yes, jump ;AN000; + jmp Parse_Exit ; no, invalid drive id , exit ;AN000; + +Set_Drive_Id: + inc num_of_drives ; update the drive count ;AN000; + xor ax,ax ;AN000; + mov ax,valuelo ; get drive number ;AN000; + xor ah,ah ; only low byte is valid ;AN000;;AN000; + mov di,ParmBuff_Ptr ; DS:DI-->driveID buffer ;AN000; + dec ax ; C:=2 D:=3 E:=4 etc Fastopen drive id ;AN000; + mov [di],ax ; save drive in Drive ID table ;AN000; + add parmbuff_ptr,2 ; points to next extent count area ;AN000; + mov al,PosTYpe ; set previous type before look for next ;AN000; + mov Prev_Type,al ; positional parameter ;AN000; + mov si,Next_Parm ; get pointer to next param (switch) ;AN000; + mov Current_Parm,si ; ;AN000; + jmp Parse_Loop ; look for next posistional parameter ;AN000; + + +;---------------------------------------------------------------------------- +; PROCESS INTEGER ( C:=n ) followed by drive ID +;---------------------------------------------------------------------------- +PROC_NAME: + cmp Prev_Type, 6 ; previous type = drive ID + je Get_Name_Value ; yes - jump + mov ax,incorrect_param ; error code ;AN000; + jmp bad_param + +Get_Name_Value: + xor ax,ax ;AN000; + mov ax,valuelo ; get name value ;AN000; + cmp ax,10 ; check validity of the count ;AN000; + jl Bad_Name_Count + cmp ax,999 ;AN000; + jle save_name_count ; count OK, save it ;AN000; + +Bad_Name_Count: ; bad name count + mov ax,Invalid_Name ; error code ;AN000; + jmp parse_error ; error - exit ;AN000; + +Save_Name_Count: + mov name_count,ax ; save it (name count) + add Total_Name_Count,ax ; update total name count + mov di,ParmBuff_Ptr ; DS:DI-->driveID buffer ;AN000; + mov ax,-1 ;AN000; + mov [di],ax ; MARK this drive has no extent entry ;AN000; + add parmbuff_ptr,2 ; points to extent count area ;AN000; + +Set_Drive_Hdr: + mov ax,Name_Count ; get name count entry ;AN000; + CALL SET_DRIVE_CACHE_HEADER ; Set Name cache header ;AN000; + jnc set_min_max ; no error set min and max ;AN000; + jmp parse_Error ; display error ;AN000; + +Set_Min_Max: + mov al,1 ;AN000; + mov Par_Min,al ; change min-max ;AN000; + mov al,2 ;AN000;;AN000; + mov Par_Max,al ;AN000; + mov al,PosTYpe ; set previous type before look for next ;AN000; + mov Prev_Type,al ;AN000; + mov si,Next_Parm ; get pointer to next param (switch) ;AN000; + mov Current_Parm,si ; ;AN000; + mov ordinal,0 ;AN000; + Jmp Parse_Loop ; parse nexy positional ;AN000; + + +;---------------------------------------------------------------------------- +; PROCESS COMPLEX (n,m) followed by a drive id +;---------------------------------------------------------------------------- +PROC_COMPLEX: + cmp Prev_Type, 6 ; previous type = drive ID ?? + je Get_Cmplx_Item ; yes - ok + mov ax,incorrect_param ; no - error, previous must be drive id ;AN000; + jmp bad_param ; display error + +Get_Cmplx_Item: + mov al, PosType ; + mov Prev_Type,al ; save current type as previous + lea di,valuelo ; DI-->result buffer ;AN000; + mov si,[di] ; get next positional param address ;AN000; + mov current_parm,si ; SI-->first complex item ;AN000; + mov ax,08001h ; Control ( Numeric/Optional ) ;AN000; + mov Pos1Type,ax ; change pos-param control block flag ;AN000; + mov Pos2Type,ax ;AN000; + mov al,1 ; atleast 1 or maximun two positionals in complex item ;AN000; + mov Par_Min,al ; set minimum = 1 + mov al,2 ;AN000; + mov Par_Max,al ; set maximum = 2 ;AN000; + mov ordinal1,0 ; initialize ordinal for complex item loop ;AN000; + mov par_sw,0 ; reset switch flag in PARMSX + +COMPLX_LOOP: + xor dx,dx + LEA DI,PARMS ;ES:DI = PARSE CONTROL DEFINITON ;AN000; + MOV SI,CURRENT_PARM ;SI = COMMAND STRING, NEXT PARM ;AN000; + XOR DX,DX ;RESERVED, INIT TO ZERO ;AN000; + MOV CX,ORDINAL1 ;OPERAND ORDINAL, INITIALLY ZERO ;AN000; + + CALL SYSPARSE ; parse positional param in complex item + + cmp ax,NOERROR ; parse error ?? + je Chk_Complex_Result ; no, check result buffer ;AN000; + cmp ax,EOL ; END-OF-COMMAND string ?? ;AN000; + jne Complex_Error ; no, check error + mov si,Next_Parm ; Set pointer to next param (4/3/88) + mov Current_Parm,si ; set next param address before parsing ;AN000; + jmp Parse_Loop ; go to main parse loop + +Complex_Error: + mov ax,Incorrect_Param ; no, check reult buffer ;AN000; + jmp bad_param ; display error + +;------------------------------------------------------------------------------- +; Ckeck The Result Buffer +;------------------------------------------------------------------------------- +Chk_Complex_Result: + mov ordinal1,cx ; save current ordinal ;AN000; ;AN000; + cmp postype,1 ; positional type = number ?? + je Proc_Complex_Name ; yes, process name entry ;AN000; + cmp postype,3 ; positional type = String ?? + je Miss_param ; yes, process missing parameter + mov ax,incorrect_param ; no, check reult buffer ;AN000; + jmp bad_param + +Miss_Param: + mov current_parm,si ; save current chara pointer ;AN000; + jmp complx_loop ; get extent count + + +;------------------------------------------------------------------------------- +; PROCESS NAME ENTRY (n) +;------------------------------------------------------------------------------- +Proc_Complex_Name: ; PROCESS COMPLEX ITEM + mov current_parm,si ; save current chara pointer ;AN000; + cmp cx,2 ; second positional in the complex ;AN000; + je proc_extent_entry ; yes, process Extent count ;AN000; + xor ax,ax ; eles process Name Count ;AN000; + mov ax,valuelo ; get name value from result buffer ;AN000; + cmp ax,10 ; validate the name value for higher ;AN000; + jl Name_Error ; and lower boundries ;AN000; + cmp ax,Max_Entry_Num ; name entry count ok ?? + jg Name_Error ; no - error + jmp short Store_Name_Count ; yes - store it + +Name_Error: ; invalid name count + mov ax,invalid_name ; error code ;AN000; + jmp parse_error ; display error + +Store_Name_Count: + mov Name_Count,ax ; save it (name count) ;AN000; ;AN000; + add Total_name_count,ax ; update total name count ;AN000; ;AN000; + + CALL SET_DRIVE_CACHE_HEADER ; Set Name cache header ;AN000; + jc Cant_Set_Header ; jump if error ;AN000; + jmp Complx_loop ; look for extent count ;AN000; + +Cant_Set_Header: + jmp Parse_Error ; error exit + + +;------------------------------------------------------------------------------- +; PROCESS EXTENT ENTRY (m) +;------------------------------------------------------------------------------- +Proc_Extent_Entry: + mov ax,valuelo ; get extent count entry + cmp ax,1 ; validate entry between 1 an 10 ;AN000; + jl Extent_Error ;AN000; + cmp ax,10 + jl set_default_ext ; if <10 set default entry 12 + cmp ax,Max_Entry_Num ; >999 ?? + jg Extent_Error ; yes - error + jmp short Store_Extent_Count ; value OK, save it + +Set_Default_Ext: ; for count 1 throug 9 set default count 12 + mov ax,12 + jmp short Store_Extent_Count + +Extent_Error: ; invalid entry error + mov ax,invalid_extent ; error code + jmp parse_error ; display error ;AN000; + +Store_Extent_Count: + mov ext_count,ax ; save the count + add Total_Ext_count,ax ; update total extent count + mov di,parmbuff_ptr ; DI-->drive/extent buffer ;AN000; + mov [di],ax ; save in buffer ;AN000; + add parmbuff_ptr,2 ; move pointer to next extent in buffer ;AN000; + mov si,Next_Parm ; get pointer to next param + mov Current_Parm,si ; set next param address before parsing ;AN000; + mov Par_Sw,1 ; set switch flag in PARMSX + Jmp Parse_Loop ; parse next positional parameter ;AN000; + + +;---------------------------------------------------------------------------- +; PROCESS SWITCH (/X) OPTION +;---------------------------------------------------------------------------- +Proc_Switch: + cmp Prev_Type,0 ; any previous type ?? + je Switch_Error ; no - error + cmp Ext_Mem,0 ; switch previously specified ?? ;AN000; + je set_sw_flag ; no, set flag ;AN000; + +Switch_Error: + mov ax,incorrect_param ; error code ;AN000; + jmp bad_param ; error - /x could be specified only once + +Set_Sw_flag: + cmp Prev_Type,6 ; previous param = drive ID 12/15 P2939 ;AN000; + jne sw_save_Ptr ; no - continue 12/15 p2939 ;AN000; + ;AN000; + CALL PROC_DEFAULT ; yes setup default counts for previous drive ;AN000; + jnc sw_save_ptr ; no error - continue 12/15 p2939 ;AN000; + jmp short parse_Error ; error - exit 12/15 P2939 ;AN000; + +Sw_save_ptr: + mov current_parm,si ; save current chara pointer ;AN000; + mov bx,synonym ; get synonym (/x) ;AN000; ;AN000; + cmp bx,offset e_switch ; /X ?? ;AN000; + je set_extflag ; yes - check result buffer ;AN000; + jmp Bad_Switch ; error exit + +Set_ExtFlag: ; no, check reult buffer + mov Ext_Mem,1 ; yes, set Hi Memory flag ;AN000; + mov si,Current_parm ; -->next parameter ;AN000; + mov al,PosTYpe ; set prevvious type before look for next ;AN000; + mov Prev_Type,al ;AN000; + jmp parse_loop ;AN000; + +Bad_Switch: + mov di,Next_Parm ; ending address of bad param 1/6/88 + mov al,0 + mov ds:[di],al ; set termination character + LEA SI,SUBLIST1 ; DS:SI-->Substitution list ;AN000; + MOV AX,CURRENT_PARM ; starting address of bad parameter ;AN000; + MOV [SI].DATA_OFF,AX ; SI-->File name ;AN000; + MOV [SI].DATA_SEG,DS ; DS-->Segment ;AN000; + MOV [SI].MSG_ID,0 ; message ID ;AN000; + MOV [SI].FLAGS,010H ; ASCIIZ string, left align ;AN000; + MOV [SI].MAX_WIDTH,0 ; MAXIMUM FIELD WITH ;AN000; + MOV [SI].MIN_WIDTH,0 ; MINIMUM FIELD WITH ;AN000; + MOV BX,Invalid_Switch ; get message number + MOV MSG_NUM,BX ; set message number ;AN000; + MOV SUBST_COUNT,1 ; substitution count ;AN000; + MOV MSG_CLASS,-1 ; message class ;AN000; + MOV INPUT_FLAG,0 ; no input ;AN000; + CALL PRINT_STDOUT ; display message ;AN000; + stc ; error flag + jmp Parse_Exit ; exit (1/6/88 P2670) + + + +;---------------------------------------------------------------------------- +; PROCESS PARSE ERROR +;---------------------------------------------------------------------------- +PARSE_ERROR: ; AX = meassage number + MOV MSG_CLASS,-1 ; message class ;AN000; + MOV MSG_NUM,AX ; set message number ;AN000; + MOV SUBST_COUNT,0 ; no message substitution ;AN000; + MOV INPUT_FLAG,0 ; no input ;AN000; + CALL PRINT_STDOUT ; show message ;AN000; + stc ; set error flag ;AN000; + +Parse_Exit: ; EXIT + push cs ;AN000; + pop ds ; DS - Program data area seg ;AN000; + ret ;AN000; ;AN000; +PARSE ENDP ; end of parser + + + + +;---------------------------------------------------------------------------- +; +; Procedure: PROC_DEFAULT +; +; Function: Process default parameters if name and extend counts +; are not specified with the drive id. +; +;---------------------------------------------------------------------------- + +PROC_DEFAULT PROC ; PROCESS DEFAULT + push si ; makesure to save next chara pointer ;AN000; + mov ax,30h ; get default name count ;AN000; + mov name_count,ax ; save it ;AN000; + add Total_name_count,ax ; update total name count ;AN000; + mov ext_count,ax ; save it ;AN000; ;AN000; + add Total_Ext_count,ax ; save it ;AN000; ;AN000; + mov di,ParmBuff_Ptr ; DS:DI-->parameter buffer ;AN000; + mov [di],ax ; save in buffer ;AN000; + add Parmbuff_ptr,2 ; points to next drive id position + mov ax,Name_Count ;AN000; + CALL Set_drive_Cache_Header ; Set Name cache header ;AN000; + +Default_Exit: + pop si ;AN000; + ret ; return ;AN000; + +PROC_DEFAULT ENDP + + + + +;---------------------------------------------------------------------------- +; Procedure: VERIFY_COUNTS +; +; Function: Verify the validity of the name and extent counts + +;---------------------------------------------------------------------------- +VERIFY_COUNTS PROC NEAR + +; Check the validity of NAME and EXTENT count entries + cmp Total_ext_count,0 ; any extent param ?? ;AN000; + je Chk_Name_Count ; no, dont check extent count ;AN000; + cmp Total_ext_count, Max_Entry_Num ; check lower boundry ;AN000; + jg invalid_ext ; error if not within ;AN000; + clc ; Extent Count is valid + +; Extent count is OK, check Name count +Chk_Name_Count: + cmp Total_Name_Count,0 ; any name param ?? ;AN000; + je Verify_Exit ; no, dont check extent count ;AN000; + + cmp Total_name_count, Max_Entry_Num ;AN000; + jg invalid_name_entry ;AN000; + clc ; Name count is OK ;AN000; + jmp short verify_exit ; exit ;AN000; + +Invalid_ext: + mov ax,many_ext_entries ; AX = error code ;AN000; + stc + jmp short verify_exit ;AN000; + +Invalid_name_entry: + mov ax,many_name_entries ; AX = error code ;AN000; + stc ;AN000; + +Verify_Exit: ; + + RET ;AN000; + +VERIFY_COUNTS ENDP + + + + + + + + + + + +;========================================================================= +; CHECK_DRIVE +;----------------------------------------------------------------------- +; +; INPUT: AL - Drive letter +; +; OUTPUT: +; If Carry = 0 +; user_drive set to current entered drive letter +; num_Of_drives incremented +; If Carry = 1 error +;----------------------------------------------------------------------- +; 1) see if drive is valid and removable using int 21h IOCTL +; +; 2) use int 21h name translate to make sure that the drive is not +; redirected, substed, on another machine, or in any other way shape +; or form hosed. +;========================================================================= + +CHECK_DRIVE PROC NEAR + + CALL Convert_To_Caps ; make sure it is a capital letter + mov byte ptr user_drive,al ; save it in user drive + mov byte ptr source_xname,al ; put in source string for call + + mov bl,al ;put drive letter in bl + sub bl,"A"-1 ;convert to 1 based number + + mov ah,ioctl ;set up for removable call + mov al,8 ;function code + INT int_command + + cmp ax,1 ;is drive fixed? + jz okay_drive ;yes - see if it's subst + cmp ax,0fh ;is drive valid? + jnz hosed_drive ;yes - but hosed + + mov ax,invalid_drive ; set bad drive message + jmp short drive_Error ; display error message + +Okay_Drive: + lea si,source_xname ; set up for name translate + lea di,target_xname + mov ax,xNameTrans SHL 8 + INT int_command ;do the translation + + lea si,source_xname ;compare source and target drive + lea di,target_xname + + mov cx,Len_source_xname ;get count of invalid chars + repz cmpsb ;compare until mismatch found + jz check_drive_end ;no mismatch - exit + +Hosed_Drive: + MOV AX,BAD_USE_MESSAGE ; message number + +Drive_Error: + push ax ; save message number + mov ax,Valuelo ; get drive letter number from result buff + ; C:=3 D:=4 etc, Parser drive id convention + add al,040H ; convert to drive letter + lea si,Drive_Id ; DS:SI-->drive letter save area + mov [si],al ; save drive letter in buffer + + LEA SI,SUBLIST1 ; DS:SI-->Substitution list ;AN000; + MOV AX,OFFSET DRIVE_ID ;AN000; + MOV [SI].DATA_OFF,AX ; SI-->File name ;AN000; + MOV [SI].DATA_SEG,DS ; DS-->Segment ;AN000; + MOV [SI].MSG_ID,1 ; message ID ;AN000; + MOV [SI].FLAGS,010H ; ASCIIZ string, left align ;AN000; + MOV [SI].MAX_WIDTH,0 ; MAXIMUM FIELD WITH ;AN000; + MOV [SI].MIN_WIDTH,0 ; MINIMUM FIELD WITH ;AN000; + POP AX ; restore message number ;AN000; + MOV MSG_NUM,AX ; set message number ;AN000; + MOV SUBST_COUNT,1 ; substitution count ;AN000; + MOV MSG_CLASS,-1 ; message class ;AN000; + MOV INPUT_FLAG,0 ; no input ;AN000; + CALL PRINT_STDOUT ; display message ;AN000; + stc ; error flag + +Check_Drive_End: + ret ; return + +CHECK_DRIVE endp + + + + + +;========================================================================= +; Procedure: SET_DRIVE_CACHE_HEADER +; +; Function: Set name cache drive header +; +; Input: ax contains number of entries for num_entries +; user_drive contains user drive for drive_letter +; num_Of_drives contains number of caches set up so far +; drive_cache offset of drive cache headers start +; Output: +; If successful: +; drive cache header set up +; user_drive reset to blank +; num_Of_drives incremented +; else +; bx set to error flag +; dx points to error message +;----------------------------------------------------------------------- +; 1) see if drive too many drives have been entered. +; 2) Walk through drive cache headers to make sure that the drive +; letter was not previously entered. +; 3) Set up drive cache header +;========================================================================= + +SET_DRIVE_CACHE_HEADER PROC NEAR + + mov cx,num_of_drives ;get current count of drives + mov bx,offset drive_cache ;get start of name drive cache + mov dl,user_drive ;get user entered drive + dec cx ;is this the 1st drive entered ? + jcxz set_it_up ;yes - don't check + + cmp num_Of_drives,max_drives ;no - check for maximum num of drives + jng we_have_room ;yes - go check for dup drives + mov ax,too_many_entries ;set up for error message + stc ;set up error flag + jmp short set_dheader_exit ;and exit + +;----------------------------------------------------------------------- +; Search through the drive headers to see the duplicate drive exist. +; If a new drive header at the bottom of the chain for the new drive. +; If no drives exist, then create the new header as the first drive header. +;----------------------------------------------------------------------- +We_Have_Room: ;BX-->current drive header + cmp dl,[bx].dch_drive_letter ;drive header exist for this drive?? + jnz not_dup_drive ;no - continue + mov ax,dup_drive ;yes - set up for error message + stc + jmp short set_dheader_exit ;exit + +Not_Dup_Drive: + cmp [bx].dch_sibling_ptr,no_siblings ;any more header to search ?? + jz set_drive_sibling ;no - go create the new drive header + add bx,size drive_cache_header ;yes - get pointer to next drive header + jmp short we_have_room ;check it + +Set_drive_sibling: + mov cx,bx ;save current header address + add cx,size drive_cache_header ;pointer to next header + mov [bx].dch_sibling_ptr,cx ;set pointer to new header from current hdr + mov bx,cx ;BX-->new header + +Set_it_up: + mov [bx].dch_drive_letter,dl ;save drive letter in new header + mov [bx].dch_sibling_ptr,no_siblings ;mark new header as last header in chain + mov [bx].dch_num_entries,ax ;save name count in new header + +Set_dheader_Exit: ; Exit + ret + +SET_DRIVE_CACHE_HEADER ENDP + + + + + +subttl Convert to caps +page +;========================================================================= +; Procedure: Convert_to_caps +; +; CONVERT LOWER CASE CHARACTERS TO UPPER CASE +; Convert character in al to a capital letter. + +;========================================================================= + +CONVERT_TO_CAPS PROC NEAR + + cmp al,"a" + JNAE no_convert + cmp al,"z" + JNBE no_convert + sub al,32 + +No_Convert: + ret ;and return + +CONVERT_TO_CAPS ENDP + + + + + + + +;========================================================================= +; SET_EMS : THIS MODULE SETS EMS FOR FASTOPEN CODE AND DATA +; PAGE 0 IN HIGH MEMORY IS MAPPED FOR CODE USING +; THE PHYSICAL PAGE FRAME AND PAGE 1 IS +; MAPPED FOR DATA USING PHYSICAL PAGE FRAME NUMBER +; TWO PHYSICAL PAGE FRAME SEG IDs ARE SAVED AND +; THEY WILL BE USED BY THE (MAIN) ROUTINE. +; +; INPUTS : NONE +; +; OUTPUTS : CY - ERROR +; +; NC - EMS_PAGE_SEG - SEG ID OF SINGLE PAGE FRAME +;========================================================================= + +SET_EMS PROC NEAR + CALL EMS_CHECK1 ;SEE IF EMS INSTALLED ;AN000; + JNC EMS_GET_PAGE ; yes, get page ;AN000; + + MOV EMS_FLAG,0 ; Flag EMS not installed ;AN000; + STC ; Make sure carry is Clear ;AN000; + JMP EMS_EXIT ; Leave check routine ;AN000; + +EMS_GET_PAGE: + PUSH ES ; save ES,DI they may destroy by 2F + PUSH DI + +IF NOT BUFFERFLAG + + MOV AH,EMS_2F_HANDLER + XOR AL,AL + INT 2FH ; see 2F is there + CMP AL,0FFH + JNE EMS_PAGE_ERR ; error, if not + + MOV AH,EMS_2F_HANDLER + MOV AL,0FFH + MOV DI,0FEH + INT 2FH ; get EMS page + OR AH,AH + JNZ EMS_PAGE_ERR + MOV EMS_PAGE_SEG,ES ; SAVE PAGE SEG ID + MOV EMS_PAGE_NUM,DI ; SAVE PHYSICAL PAGE NUMBER + +ELSE + +;---------------------------------------------------------------HKN 8/25/88 +; Fastopen must get an EMS page like a well behaved program and +; should not grab a reserved page from the BIOS. +; + mov cx, FRAME_COUNT + xor ax, ax + mov bx, ax + mov dx, ax + +get_page: + cmp es:[di], 0a000h ; is the page in ax above 640K + jb next_page ; if no get next_page + + mov bx, di ; we have a valid page + + inc dx ; count the # of pages above 640K + + cmp dx, 1 + je next_page + sub di, 4 + mov ax, es:[di] + mov [FST_PAGE], ax + mov ax, es:[di+2] + mov [FST_PAGE+2], ax + mov di, bx ; restore di + +next_page: + add di, 4 + loop get_page + jne found_page + jmp ems_page_err + +found_page: +; int 3 + cmp dx, 1 + jne second_last_page + mov di, bx + mov ax, es:[di] + mov ems_page_seg, ax + mov ax, es:[di+2] + mov ems_page_num, ax + jmp save_state + +second_last_page: + mov ax, [FST_PAGE] + mov ems_page_seg, ax + mov ax, [FST_PAGE+2] + mov ems_page_num, ax + +save_state: + push es + mov ax, Cseg_Main + mov es, ax + assume es:Cseg_Main + + mov word ptr save_map_addr, offset es:save_ems_page_state + mov word ptr save_map_addr + 2, ax + + mov ax, ems_page_seg + mov es:Main_EMS_PAGE_SEG, ax + pop es + assume es:Cseg_Init + call [save_map_addr] + jc ems_page_err + +;-------------------------------------------------------------------------- + +ENDIF + + POP DI + POP ES + JMP SHORT EMS_ALLOCATE_PAGE + +EMS_PAGE_ERR: + POP DI + POP ES + STC ;yes, page not found ;AN000; + JMP SHORT EMS_ERROR ;error exit ;AN000; + +;----------------------------------------------------------------------- +; Allocate one page +;----------------------------------------------------------------------- +EMS_ALLOCATE_PAGE: + MOV BX,1 ;one page ;AN000; + MOV AH,EMS_ALLOC_PAGES ;set op code ;AN000; + INT EMS_INT ;allocate page ;AN000; + OR AH,AH ;Was there an error allocating? ;AN000; + JNZ EMS_ERROR ;yes - display error ;AN000; + MOV EXT_HANDLE,DX ;no -Save EMS handle + +IF BUFFERFLAG + +;------------------------------------------------------HKN 8/25/88 +; Must save ems handle in Cseg_Main also. + + push es + push ax + mov ax, Cseg_Main + mov es, ax + assume es:Cseg_Main + mov es:ems_save_handle1, dx + pop ax + pop es + assume es:Cseg_Init + +ENDIF + +;----------------------------------------------------------------------- +; SET HANDLE NAME TO THE PAGE HANDLE +;----------------------------------------------------------------------- + PUSH DS ;AN000; + POP ES ;AN000; + ASSUME ES:CSEG_INIT ;AN000; + LEA SI,HANDLE_NAME ; DS:SI-->Handle name string ;AN000; + MOV DX,EXT_HANDLE ; handle number ;AN000; + MOV AH,EMS_HANDLE_NAME ;AN000; + MOV AL,1 ; set op code code ;AN000; + INT 67H ; set handle ;AN000; + OR AH,AH ;AN000; + JNZ EMS_ERROR ; jump if error ;AN000; + +;----------------------------------------------------------------------- +; Map logical page 0 in physical page frame FE (P254) +;----------------------------------------------------------------------- + CALL MAP_FRAME ;map two pages ;AN000; + JNC EMS_GET_SIZE ;no error, normal exit ;AN000; + +;----------------------------------------------------------------------- +; Get partial page map size +;----------------------------------------------------------------------- +EMS_GET_SIZE: + MOV AH,EMS_PAGE_SIZE ;Allocate requested pages ;AN000; + MOV AL,2 + INT EMS_INT ; ;AN000; + OR AH,AH + JNZ EMS_ERROR + XOR AH,AH + MOV EMS_PAGESIZE,AX ;save EMS page size + CLC + JMP SHORT EMS_EXIT + +EMS_ERROR: + MOV AX,EMS_FAILED ;error message ;AN000; + MOV MSG_NUM,AX ;save message number + MOV SUBST_COUNT,0 ;no message substitution ;AN000; + MOV MSG_CLASS,-1 ;message class ;AN000; + MOV INPUT_FLAG,0 ;no input ;AN000; + CALL PRINT_STDOUT ;show message "Incorrect Parameter" ;AN000; + STC ; set error flag ;AN000; + +EMS_EXIT: + RET ; Return ;AN000; + +SET_EMS ENDP + + + + + + +;========================================================================= +; EMS_CHECK1 : THIS MODULE DETERMINES WHETHER OR NOT EMS IS +; INSTALLED FOR THIS SESSION. +; +; INPUTS : NONE +; +; OUTPUTS : ES:BX - FRAME ARRAY +; CY - EMS NOT AVAILABLE +; NC - EMS AVAILABLE +;========================================================================= + +EMS_CHECK1 PROC NEAR ;EMS INSTALL CHECK + + PUSH DS ;save ds ;AN000; + XOR AX,AX ;set ax to 0 ;AN000; + MOV DS,AX ;set ds to 0 ;AN000; + CMP DS:WORD PTR[067h*4+0],0 ;see if int 67h is there ;AN000; + POP DS ;restore ds ;AN000; + JE EMS_NOT_INST1 ;no, EMS not installed ;AN000; + + MOV AH,EMS_GET_STATUS ;YES, GET STATUS ;AN000; + INT EMS_INT ;INT 67H ;AN000; + CMP AH,0 ;EMS MANAGER PRESENT ?? + JNE EMS_NOT_INST1 ;NO, EMS NOT INSTALLED + + MOV AH,EMS_GET_VERSION ;YES, GET STATUS ;AN000; ;AN000; + INT EMS_INT ;INT 67H ;AN000;;AN000; + CMP AH,0 ;EMS MANAGER PRESENT ?? ;AN000; + JNE EMS_NOT_INST1 ;NO, EMS NOT INSTALLED ;AN000; + + CMP AL,40H ;VERSION 4.0 ?? ;AN000; + JNE EMS_NOT_INST1 ;NO, EMS NOT INSTALLED ;AN000; + + MOV AX,EMS_GET_COUNT + INT EMS_INT ;GET ARRAY COUNT + CMP AH,0 + JNE EMS_NOT_INST1 + + MOV FRAME_COUNT,CX + MOV AX, BUFFER_ENTRY_SIZE + MUL CX ; CALCULATE THE ARRAY SIZE BE RESERVED + +IF NOT IBMCOPYRIGHT + CMP AX, 100h +ELSE + CMP AX, 30H +ENDIF + + JG EMS_NOT_INST1 + + MOV AX,EMS_GET_FRAME_ADDR ;YES, GET FRAME ADDRESS ;AN000; + PUSH DS ;SWAP DS & ES ;AN000; + POP ES ; ;AN000; + LEA DI,FRAME_BUFFER ;ES:DI--> RESULT BUFFER ;AN000; + INT EMS_INT ;GET FRAME ADDRESSES ;AN000; + CMP AH,0 ;IS EMS INSTALLED ;AN000; + JNE EMS_NOT_INST1 ;NO,exit + CMP CX,FRAME_COUNT ; ;AN000; + JNE SHORT EMS_NOT_INST1 + + CLC + MOV EMS_FLAG,1 ; EMS IS ACTIVE, SET FLAG + JMP EMS_CHECK1_EXIT + +EMS_NOT_INST1: ;EMS NOT INSTALLED + MOV AX,EMS_NOT_INSTALL ;error message ;AN000; + MOV MSG_NUM,AX ;set message number ;AN000; + MOV SUBST_COUNT,0 ;no message substitution ;AN000; + MOV MSG_CLASS,-1 ;message class ;AN000; + MOV INPUT_FLAG,0 ;no input ;AN000; + CALL PRINT_STDOUT ;show message + STC ;FLAG EMS NOT INSTALLED ;AN000; + ;AN000; +EMS_CHECK1_EXIT: ;EXIT ROUTINE + RET ;RETURN TO CALLER ;AN000; + +EMS_CHECK1 ENDP + + + + +;========================================================================= +; MAP_FRAME : THIS MODULE MAPS TWO LOGICAL PAGES IN THE HIGH +; MEMORY TO TWO PHYSICAL PAGE FEAMES IN THE LOW +; MEMORY. +; +; INPUTS : EXT_HANDLE - HANDLE +; +; OUTPUTD CY - ERROR +; NC - PAGE IS MAPPED +;========================================================================= + +MAP_FRAME PROC NEAR ; MAP physical page frames + PUSH BX ; DMS; + XOR BX,BX ; Logical page 0 ;AN000; + MOV AX,EMS_PAGE_NUM ; AL=Physical Page frame number ;AN000; + MOV AH,EMS_MAP_HANDLE ; AH=EMS function to map page ;AN000; + MOV DX,EXT_HANDLE ; EMS handle ;AN000; + INT EMS_INT ;AN000; + OR AH,AH ; Was there an error allocating? ;AN000; + JNZ MAP_ERROR ; yes - set flag ;AN000; + CLC + JMP SHORT MAP_EXIT ; no - exit ;AN000; + +MAP_ERROR: + STC ; set error flag ;AN000; + +MAP_EXIT: + POP BX ;AN000; + RET ; return ;AN000; + + +MAP_FRAME ENDP + + + + + + + + +;************************************************************ +;* +;* SUBROUTINE NAME: PRINT_STDOUT +;* +;* SUBROUTINE FUNCTION: +;* Display the requested message to the specified handle +;* +;* INPUT: +;* Paramters in parater storage area +;* DS:SI-->Substitution List +;* ES:DI-->PTR to input buffer if buffered keyboard +;* input is specified (DL = 0A) +;* OUTPUT: +;* AX = Single character entered if DL=01 +;* OR +;* ES:DI-->input buffer where string is returned if DL=0A +;* +;* The message corresponding to the requested msg number will +;* be written to Standard Out. Message substitution will +;* be performed if specified +;* +;* NORMAL EXIT: +;* Message will be successfully written to requested handle. +;* +;* ERROR EXIT: +;* None. Note that theoretically an error can be returned from +;* SYSDISPMSG, but there is nothing that the application can do. +;* +;* INTERNAL REFERENCES: SysDispMsg +;* +;* EXTERNAL REFERENCES: +;* None +;* +;************************************************************ +PRINT_STDOUT PROC NEAR + PUSH BX ;AN000; + PUSH CX ;AN000; + PUSH DX ;AN000; + + MOV AX,MSG_NUM ; Message ID ;AN000; + MOV BX,STDOUT ; standard input message handle ;AN000; + MOV CX,SUBST_COUNT ; message substitution count ;AN000; + MOV DH,MSG_CLASS ; message class ;AN000; + MOV DL,INPUT_FLAG ; Type of INT 10 for KBD input ;AN000; + + CALL SYSDISPMSG ; AX=Extended key value if wait ;AN000; + ;for key ;AN000; + JNC DISP_DONE ; If CARRY SET then registers + ;will contain extended error info ;AN000; + ; AX - Extended error Number + ; BH - Error Class + ; BL - Suggested action +DISP_DONE: ; CH - Locus + POP DX ;AN000; + POP CX ;AN000; + POP BX ;AN000; + ;AN000; + RET +PRINT_STDOUT ENDP + + +CSEG_INIT ENDS + + +;=========================================================================== +;;; STACK SEGMENT SIZE = 20 PARAGRAPHS +;=========================================================================== + +STACK SEGMENT PARA STACK 'STACK' + DB 64 dup("STACK ") ; 512 WORD STACK AREA ;AN000; +STACK ENDS + + +END START + diff --git a/v4.0/src/CMD/FASTOPEN/FASTOPEN.ASM b/v4.0/src/CMD/FASTOPEN/FASTOPEN.ASM new file mode 100644 index 0000000..5594abd --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTOPEN.ASM @@ -0,0 +1,2052 @@ + Page 84,132 ; +Title FASTOPEN +;Date: May 13,1988 +;============================================================================== +; EQUATES +;============================================================================== +Is_drive_head EQU 00000001b ;AN000; +Is_delete EQU 00000010b ;AN000; +Is_insert EQU 00000100b ;AN000; +Not_drive_head EQU 11111110b ;AN000; +Not_delete EQU 11111101b ;AN000; +Not_insert EQU 11111011b + +EMS_SAVE_STATE EQU 4FH ;AN000; +EMS_RESTORE_STATE EQU 4FH ;AN000; +EMS_INT EQU 67H ;AN000; +DOS_PAGE1 EQU 0FEH ;AN000; + + +;============================================================================== +; INCLUDE FILES +;============================================================================== +.xcref +.xlist +debug=0 ; an equate only for DOSMAC.inc ;AN000; +INCLUDE DOSMAC.inc ;AN000; +.list +.cref +INCLUDE dirent.inc ;AN000; +INCLUDE fastsegs.inc ; this cannot include in Fastopen.inc +INCLUDE fastopen.inc ; this include file also contains DOS equates ;AN000; +include version.inc + +;============================================================================== + + + +EXTRN FK_OPEN:FAR ;AN000; +EXTRN FK_CLOSE:FAR ;AN000; +EXTRN FK_INSERT:FAR ;AN000; +EXTRN FK_DELETE:FAR ;AN000; +EXTRN FK_LOOKUP:FAR ;AN000; +EXTRN FK_TRUNCATE:FAR ;AN000; +EXTRN FK_PURGE:FAR ;AN000; + + +;============================================================================ + +CSEG_MAIN SEGMENT PARA PUBLIC 'code' + ASSUME cs:cseg_main, ds:nothing,es:nothing,ss:nothing +;============================================================================ + +PUBLIC MAIN ;AN000; + +IF BUFFERFLAG +PUBLIC SAVE_EMS_PAGE_STATE +PUBLIC EMS_PAGE_NUMBER +ENDIF + +PUBLIC RESTORE_PAGE_STATE +PUBLIC EMS_SAVE_HANDLE1 + +PUBLIC Main_name_cache_seg ;AN000; +PUBLIC Main_Num_Of_drives ;AN000; +PUBLIC Main_Ext_Count ;AN000; +PUBLIC Main_extent_drive_Buff ;AN000; +PUBLIC Main_ext_cache_size ;AN000; +PUBLIC Main_name_cache_Buff ;AN000; +PUBLIC Main_EMS_FLAG ;AN000; +PUBLIC Main_Res_Segs ;AN000; +PUBLIC Main_EMS_PAGE_SIZE ;AN000; +PUBLIC Main_EMS_PAGE_SEG ;AN000; +PUBLIC Main_Total_Ext_Count ;AN000; +PUBLIC Main_Total_Name_Count ;AN000; +PUBLIC Main_Name_Drive_Buff ;AN000; +PUBLIC Main_ParamBuff ;AN000; + +PUBLIC FOPEN_Insert ;AN000; +PUBLIC FOPEN_Update ;AN000; +PUBLIC FOPEN_Delete ;AN000; +PUBLIC FOPEN_Lookup ;AN000; +PUBLIC FOPEN_PURGE ;AN000; + +PUBLIC FSEEK_Open ;AN000; +PUBLIC FSEEK_Close ;AN000; +PUBLIC FSEEK_Insert ;AN000; +PUBLIC FSEEK_Delete ;AN000; +PUBLIC FSEEK_Lookup ;AN000; +PUBLIC FSEEK_Truncate ;AN000; +PUBLIC FSEEK_Purge ;AN000; + +PUBLIC VECTOR_LookUp ;AN000; +PUBLIC VECTOR_Delete ;AN000; + + +; Following data variables are accessed by all other segments +call_cnt DW 0 ;AN000; +Purge_Flag DW 0 ; =1 if last call is PURGE function +Prev_drv_id DB -1 ; previous request drive id +Main_name_cache_seg DW Cseg_Init ; default to Init1 seg ;AN000; +Main_Num_Of_drives DW 0 ; number of drives ;AN000; +Main_Ext_Count DW 0 ; total name extent entries ;AN000; +Main_extent_drive_Buff DW 0 ; addrs to extent drive ;AN000; +Main_name_cache_Buff DW 0 ; address of Name cache buffer ;AN000; +Main_ext_cache_size DW 0 ; extent cache size +Main_EMS_FLAG DW 0 ; EMI flag 1= if EMI is enabled ;AN000; +Main_Res_Segs DW 0 ; number of segs to be stay resident ;AN000; +Main_Total_Ext_Count DW 0 ; Total extent count entries ;AN000; +Main_Total_Name_Count DW 0 ; Total name count entries ;AN000; +Main_Name_Drive_Buff DW 0 ; EMS data page segment ID ;AN000; +Main_ParamBuff DW 50 dup (0) ; Drive ID/extent count buffer ;AN000; + +; The following structure is for saving and restoring EMS page state +EMS_PAGE_MAP LABEL WORD +Main_EMS_SEG_COUNT DW 1 ; EMS segment count +Main_EMS_PAGE_SEG DW 0 ; EMS page segment ID ;AN000; + + +Main_EMS_PAGE_SIZE DW 0 ; EMS page size ;AN000; +EMS_PAGE_ARRAY DW 30 dup (0) ; EMS state save array + +; The following data values are used by MAIN segment +EMS_SAVE_LOG_PAGE1 DW ? ;HOLDS PREVIOUS PAGE1 ;AN000; +EMS_SAVE_HANDLE1 DW ? ;HOLDS PREVIOUS handle1 ;AN000; + +IF BUFFERFLAG +;----------------------------------------------------------HKN 8/26/88 + +EMS_PAGE_NUMBER DW ? ; holds the ems + ; physical page no. + +ENDIF +; +;----------------------------------------------------------------------------- +; Fastopen/Fastseek function jump vectors +; Inititally the jump vectors have default offset and segment values. +; If the modules are relocated, the offset and the segID in the jump vectors +; may be changed to the new segID of the new location. +;----------------------------------------------------------------------------- +FOPEN_Insert DD Insert ;AN000; +FOPEN_Update DD Update ;AN000; +FOPEN_Delete DD delete ;AN000; +FOPEN_Lookup DD lookup ;AN000; +FOPEN_Purge DD FP_purge ;AN000; + +FSEEK_Open DD Fk_Open ;AN000; +FSEEK_Close DD Fk_Close ;AN000; +FSEEK_Insert DD Fk_Insert ;AN000; +FSEEK_Delete DD Fk_Delete ;AN000; +FSEEK_Lookup DD Fk_Lookup ;AN000; +FSEEK_Truncate DD Fk_Truncate ;AN000; +FSEEK_Purge DD Fk_Purge ;AN000; + +VECTOR_LookUp DD LookUp ; jump vector to LookUp used by Insert call +VECTOR_Delete DD Fk_Delete ; jump vector to Delete used by Free_buffer routine + + + + + +;============================================================================== + +MAIN PROC FAR ; FAR procedure for FAR call from DOS + push cx ; save DOS registers ;AN000; + push dx ; makesure to restore the necessary ;AN000; + push ds ; ones on return ;AN000; + push es ;AN000; + push bp ;AN000; + push di ;AN000; + push bx ;AN000; + +;----------------------------------------------------------------------------- +; The cache buffers are maintained in a seperate segement whose segment ID is +; in Name_Cache_Seg. The ES will be used as the seg register during the access +; of data in the cache buffers, while DS will be used to access the Fastopen +; resident and non-resident data area. +;----------------------------------------------------------------------------- + cmp cs:Main_EMS_flag,1 ; EMS enabled ?? ;AN000; + jne dispatch_funcs ; no - dispatch functions ;AN000; + ; yes - save EMS page state +IF NOT BUFFERFLAG + +;----------------------------------------------------------------------------- +; SAVE EMS PAGE STATE +;----------------------------------------------------------------------------- + PUSH AX ; save registers + PUSH CX + PUSH DX ;AN000; + PUSH DS ;AN000; + PUSH ES ;AN000; + PUSH BP ;AN000; + PUSH SI ;AN000; + PUSH DI ;AN000; + PUSH BX ;AN000; + MOV AX, SEG EMS_PAGE_MAP ; get segid + MOV DS,AX + LEA SI,EMS_PAGE_MAP ; DS:SI-->page map struc + MOV AX, SEG EMS_PAGE_ARRAY ; get segid + MOV ES,AX + LEA DI,EMS_PAGE_ARRAY ; ES:DI-->Page ARRAY + MOV AH,EMS_SAVE_STATE ; + MOV AL,0 ; subfunction code + INT EMS_INT ; save page state ;AN000; + + POP BX ;AN000; + POP DI ;AN000; + POP SI ;AN000; + POP BP ;AN000; + POP ES ;AN000; + POP DS ;AN000; + POP DX ;AN000; + POP CX ;AN000; + + CMP AH,0 ; save ok?? + JNE SAVE_FAILED ; no, error + POP AX ; clear stack + +ELSE + + +;------------------------------------------------------------HKN 8/26/88-- +; Before dispatching off the fastopen functions we must do the +; following: +; 1. save the map for this page +; 2. map this page to log. page 0 with the fastopen handle in +; ems_save_handle1. +; 3. dispatch +; + +; int 3 + + push ax + push cx + push dx + push ds + push es + push bp + push si + push di + push bx + + call far ptr save_ems_page_state + jc ems_failed + + call map_page + jc ems_failed + + pop bx + pop di + pop si + pop bp + pop es + pop ds + pop dx + pop cx + POP AX ; restore registers + + JMP DISPATCH_FUNCS ; yes, dispatch functions + +EMS_FAILED: + pop bx + pop di + pop si + pop bp + pop es + pop ds + pop dx + pop cx + +ENDIF + +IF NOT BUFFERFLAG +SAVE_FAILED: +ENDIF + + POP AX ; restore registers + + POP BX ; no, restore DOS registers ;AN000; + POP DI ;AN000; + POP BP ;AN000; + POP ES ;AN000; + POP DS ;AN000; + POP DX ;AN000; + POP CX ;AN000; + STC + JMP ERROR_RET ; error return + + +;----------------------------------------------------------------------------- +; FASTOPEN/FASTSEEK DISPATCHER +;----------------------------------------------------------------------------- +DISPATCH_FUNCS: + cmp al,5 ; buffer purge ?? + je Check_Drive_id ; yes - check drive id + cmp al,11 ; Fastopen function call ?? ;AN000; + jge Check_drive_id ; no - dispatch Fastseek functions + jmp Dispatch_fopen ; yes - dispatch Fastopen functions ;AN000; + + +;----------------------------------------------------------------------------- +; Check to see the Drive ID in DL is the valid. If not error and return DI=1 +; if Fastseek LookUp function. Makesure to preserve AL, DS, SI and DI +;----------------------------------------------------------------------------- +CHECK_DRIVE_ID: + cmp cs:Prev_drv_id, dl ; current id same as previous valid + je Dispatch_Fseek ; yes - dont check drive ID + + push si ;AN000; + push bx ;DS=addressability to Cseg_Main ;AN000; + push cx ;AN000; + lea si,cs:Main_ParamBuff ; DS:SI-->drive ID buffer ;AN000; + mov cx,cs:Main_Num_Of_Drives ; number of drives ;AN000; + +Get_Drive_Id: ;AN000; + mov bx,cs:[si] ;AN000; + cmp bl,dl ; drive ID match ?? ;AN000; + je drive_found ; yes, drive ID found ;AN000; + add si,4 ; (2/11) no, move pointer to next ID ;AN000; + LOOP get_drive_id ; check next drive id ;AN000; + +Drive_Not_Found: ; drive id not found + pop cx ; restore registers ;AN000; + pop bx ;AN000; + pop si ;AN000; + jmp Error_Exit ; return + +Drive_Found: ; drive ID found + mov cs:Prev_drv_id,dl ; save drive id as prev drive id + pop cx ; restore registers ;AN000; + pop bx ; and do the specified function ;AN000; + pop si ;AN000; + +;----------------------------------------------------------------------------- +; FASTSEEK FUNCTION DISPATCHER +;----------------------------------------------------------------------------- +DISPATCH_FSEEK: + cmp al,010H + jle Fsk_Cont + inc cs:call_cnt ;AN000; +; cmp cs:call_cnt,0efffH ; for debugging +; jne fsk_cont ; for debugging + + +Fsk_Cont: + push cs ; set addressability + pop ds ; CS = DS = Cseg_Main segment + ASSUME ds:Cseg_Main + cmp al,FONC_Purge ; PURGE call ?? ;AN000; + je chk_05 ; yes - continue ;AN000; + + mov cs:Purge_Flag, 0 ; reset purge flag + cmp al,FSK_Open ; OPEN call ;AN000; + jne chk_12 ; jump if not ;AN000; + CALL FSEEK_OPEN ;AN000; + jmp exit ;AN000; +Chk_12: + cmp al,FSK_Close ; CLOSE ?? ;AN000; + jne chk_14 ;AN000; + CALL FSEEK_CLOSE ; process close function ;AN000; + jmp exit ;AN000; +Chk_14: + cmp al,FSK_Lookup ; LOOKUP ?? ;AN000; + jne chk_15 ;AN000; + CALL FSEEK_LOOKUP ; process lookup ;AN000; + CALL RESTORE_PAGE_STATE ; restore EMS page ;AN000; + pop dx ; dont restore original BX and DI ;AN000; + pop dx ; from DOS since BX and DI contins return values ;AN000; + jmp exit_1 ; exit + +Chk_15: + cmp al,FSK_Insert ; INSERT ?? ;AN000; + jne chk_13 ;AN000; + CALL FSEEK_INSERT ; Process insert ;AN000; + jmp exit ;AN000; +Chk_13: + cmp al,FSK_DELETE ; DELETE ?? ;AN000; + jne chk_16 ;AN000; + CALL FSEEK_DELETE ; process delete ;AN000; + jmp short exit ;AN000; +Chk_16: + cmp al,FSK_Trunc ; TRUNCATE ?? ;AN000; + jne Chk_05 ; + CALL FSEEK_TRUNCATE ; process truncate ;AN000; + jmp short exit ;AN000; + +Chk_05: + cmp cs:Purge_Flag, 1 ; previous call is purge ?? ;AN000; + jne Purge_buffs ; no - purge the buffers + clc ; yes - exit + jmp short exit ;AN000; + +Purge_Buffs: + mov cs:Purge_Flag,1 ; set purge flag + cmp CS:Main_Total_Ext_Count,0 ; reset fseek buffs?? + je reset_fopen ; no - reset fopen + CALL FSEEK_PURGE ; reset extent cache ;AN000; + +Reset_Fopen: + cmp CS:Main_Total_Name_Count,0 ; reset fopen buffs?? + je Reset_Exit ; no - reset f + CALL CS:FOPEN_PURGE ; reset extent cache ;AN000; + +Reset_Exit: + clc + jmp short exit ;AN000; + + +; NOTE: Carry Flag state from Function calls must be correctly returned +; to the DOS, especially from Fastseek Lookup function + + +;----------------------------------------------------------------------------- +; FASTOPEN FUNCTION DISPATCHER +;----------------------------------------------------------------------------- +DISPATCH_FOPEN: ; dispatch FOPEN functions + cld ;AN000; + mov cs:Purge_Flag, 0 ; reset purge flag + cmp al, FONC_update ;AN000; + jne Chk_02 ;AN000; + CALL CS:Fopen_Update ; UPDATE ;AN000; + jmp short exit ;AN000; + +Chk_02: + cmp al, FONC_insert ;AN000; + jne Chk_01 ;AN000; + CALL CS:Fopen_Insert ; INSERT ;AN000; + jmp short exit ;AN000; +Chk_01: + cmp al, FONC_look_up ;AN000; + jne chk_03 ;AN000; + CALL CS:Fopen_lookup ; LOOKUP ;AN000; + jmp short exit ;AN000; +Chk_03: + cmp al, FONC_delete ;AN000; + jne Error_Exit ;AN000; + CALL CS:Fopen_delete ; DELETE ;AN000; + jmp short exit ;AN000; + + + +;----------------------------------------------------------------------------- +; EXIT TO DOS FROM FUNCTIONS +;----------------------------------------------------------------------------- + +ERROR_EXIT: ; EXIT from invalid drive id search loop + CALL RESTORE_PAGE_STATE ; restore frame buff status ;AN000; + ; on return AX should have function code + pop bx ; restore first two regs of DOS + pop di ;AN000; + cmp al,FSK_Lookup ;AN000; + jne exit_2 ;AN000; + mov di,1 ; set error flag - invalid drive id ;AN000; + stc ;AN000; + jmp short Exit_1 ;AN000; + +EXIT_2: + clc ;AN000; + jmp short Exit_1 ;AN000; + + +; Normal Exit from Fastopen Functions except Fastseek Lookup function +EXIT: + CALL RESTORE_PAGE_STATE ; restore EMS page state ;AN000;;AN000; + pop bx ; restore BX ;AN000; + pop di ; restore DI ;AN000; + + +; Exit from FastSeek Lookup function. Dont restore BX and DI +EXIT_1: + pop bp ; restore remaining DOS registers + pop es ; except BX and DI since they contain ;AN000; + pop ds ; return values. ;AN000; + pop dx ;AN000; + pop cx ;AN000; + +ERROR_RET: + ret ;AN000; + +MAIN ENDP + +IF BUFFERFLAG +;--------------------------------------------------------------------------- +; Procedure name : save_ems_page_state +; +; Description: +; Saves the state of the page whose physical segment value is +; specified in Main_EMS_PAGE_SEG. +;--------------------------------------------------------------------------- + +SAVE_EMS_PAGE_STATE PROC FAR + + PUSH AX ; save registers + PUSH CX + PUSH DX ;AN000; + PUSH DS ;AN000; + PUSH ES ;AN000; + PUSH BP ;AN000; + PUSH SI ;AN000; + PUSH DI ;AN000; + PUSH BX ;AN000; + + MOV AX, SEG EMS_PAGE_MAP ; get segid + MOV DS,AX + LEA SI,EMS_PAGE_MAP ; DS:SI-->page map struc + MOV AX, SEG EMS_PAGE_ARRAY ; get segid + MOV ES,AX + LEA DI,EMS_PAGE_ARRAY ; ES:DI-->Page ARRAY + MOV AH,EMS_SAVE_STATE ; + MOV AL,0 ; subfunction code + INT EMS_INT ; save page state ;AN000; + + POP BX ;AN000; + POP DI ;AN000; + POP SI ;AN000; + POP BP ;AN000; + POP ES ;AN000; + POP DS ;AN000; + POP DX ;AN000; + POP CX ;AN000; + + CMP AH,0 ; save ok?? + JE SAVE_OK ; + STC + JMP SHORT DONE +SAVE_OK: + CLC +DONE: + POP AX + RET + +SAVE_EMS_PAGE_STATE ENDP + +ENDIF + + +;----------------------------------------------------------------------------- +; PROCERDURE: RESTORE_PAGE_STATE +; +; Function: Restore state of EMS page +; +; Input: None +; Output: Page is restored +; +;----------------------------------------------------------------------------- + +RESTORE_PAGE_STATE PROC NEAR ;RESTORE EMS PAGE STATE + PUSHF ;save flag ;AN000; + CMP CS:MAIN_EMS_FLAG, 0 ;EMS enabled ?? ;AN000; + JNE REST_PUSH_REGS ;yes, restore registers + JMP SHORT RESTORE_EXIT ;no, exit ;AN000; + ;yes, restore page registers +REST_PUSH_REGS: + PUSH AX ; save function code + PUSH CX ; save caller registers ;AN000; + PUSH DX ;AN000; + PUSH DS ;AN000; + PUSH ES ;AN000; + PUSH BP ;AN000; + PUSH SI ;AN000; + PUSH DI ;AN000; + PUSH BX ;AN000; + + MOV AX, SEG EMS_PAGE_ARRAY + MOV DS,AX + LEA SI,EMS_PAGE_ARRAY ; DS:SI-->Page array + MOV AH,EMS_RESTORE_STATE ; + MOV AL,1 ; + INT EMS_INT ; restre page state ;AN000; + CMP AH,0 ; restore OK ?? + JE REST_POP_REGS ; yes + STC ; set carry + +REST_POP_REGS: + POP BX ; RESTORE REGISTERS ;AN000; + POP DI ;AN000; + POP SI ;AN000; + POP BP ;AN000; + POP ES ;AN000; + POP DS ;AN000; + POP DX ;AN000; + POP CX ;AN000; + POP AX ; restore function code + +RESTORE_EXIT: + POPF + RET ;AN000; + +RESTORE_PAGE_STATE ENDP + + +IF BUFFERFLAG + +;---------------------------------------------------------HKN 8/26/88------- +; procedure name : map_page +; Inputs : ems_page_number = physical page frame +; number. +; ems_save_handle1 = emm_handle. +; Output : CY - error +; NC - page is mapped to logical page 0 +;---------------------------------------------------------------------------- +map_page proc near + + push ax + push bx + push dx + + xor bx, bx + mov ax, cs:ems_page_number ; contains the page number obtained + ; during fastopen intialization. + mov ah, 44h + mov dx, cs:ems_save_handle1 ; contains the emm handle that was + ; obtained during fast init. + int ems_int + or ah, ah + jnz err_map_page + clc + jmp short map_page_done + +err_map_page: + stc + +map_page_done: + pop dx + pop bx + pop ax + ret + +map_page endp + +ENDIF + + + ; NOTE: +CSEG_MAIN ENDS ; End of the first portion of the + ; Cseg_Main segment. Remaining + ; portion is in Fastinit.asm + +;----------------------------------------------------------------------------- + + + + + +;============================================================================== +; All Fastopen functions are kept in a seperate segment. These are accessed +; by a FAR indirect call from the MAIN routine. +; ADDRESSABILTY: CS is used for accessing local data in Cseg_Open segment +; DS is used for accessing data in the drive cache buffer +; in the Cseg_Init segment +; ES is used for accessing data in the name cache buffer +; in the Cseg_Init segment +; +;***************************************************************************** +CSEG_OPEN SEGMENT PARA PUBLIC 'code' + ASSUME cs:cseg_open,ds:nothing,es:nothing,ss:nothing +;***************************************************************************** + +PUBLIC Open_name_cache_seg ;AN000; +PUBLIC Open_name_Drive_Buff ;AN000; +PUBLIC End_Open ;AN000; +PUBLIC Chk_Flag ;AN000; + +;---- FastOpen Functions Local Variables -------------- + +Current_Node DW ? ;address of current node entry buffer ;AN000; +Current_Sibling DW ? ;address of current sibling node entry buffer ;AN000; +Current_Drive DW ? ;address of current drive header ;AN000; +Matching_Node DW -1 ;flag ;AN000; +From_Delete DW 0 ;= 1 if call is from DELETE function ;AN000; +Old_SI DW 0 ;SI save area ;AN000; +Flag DB 0 ;AN000; +Level DB 0 ;depth level of the path ;AN000; +Dir_Info_Buffer DD ? ;Dir_Info buffer inside DOS ;AN000; +Extended_Info_Buffer DD ? ;Extended Info buffer inside DOS ;AN000; +New_FEI_clusnum DW 0 ;AN000; +Packed_Name DB 11 dup (0) ;Space for packed dir name ;AN000; +Top DW 0 ;AN000; +Temp DW 0 ;AN000; +Bottom DW 0 ;AN000; +Depth DB 0 ;AN000; + +Chk_Flag dw 0 ; flag used by the analyser +func_cod db 0 ; function code for analyser + +;Following data area is filled during initialization +Open_name_cache_seg DW Cseg_Init ; address of name cache buffer +Open_name_Drive_Buff DW 0 ; address of first drive buffer + + + + +; +;============================================================================== +; Pathname Tree Search +; +; Element of each path name is represented by a node in the tree. First +; node is connected to the the Drive header through first child pointer +; (DCH_Child_Ptr). The first node may have one or more nodes underneath. +; The first one is called the Child of this node and the others are the siblings +; of the child node. Previous node is connected to the first node through +; the child pointer (nChild_Ptr) and the siblings are connected through the +; sibling pointer (nSibling_Ptr). Each node is connected to the previous +; node through a backward pointer (nBackward_Ptr). For example, to go to the +; previous node from any of the siblings. It is necessary to go to the +; child through previous siblings (if any) and then to the previous from the +; child. All this backward movement is using nBackward_Ptr. +; Similarly to go to a child or sibling, nChild_ptr or nSibling_Ptr should be +; used. The strucure of drive header and the node are defined in Fastopen.inc +; + +;============================================================================== +;Subroutine: LOOKUP +; +;INPUT: +; DS:SI -> path (drive letter D: will be validated by Find_Drive_Cache_hdr) +; ES:DI -> DIR_INFO buffer to be returned inside DOS +; ES:CX -> FASTOPEN_Extended_Info buffer inside DOS +; ES:BP -> Drive_Cache_Heade +; +; +;OUTPUT: +; If the whole path is found, +; DS:SI--> 0 +; ES:DI--> DIR_INFO buffer is filled with directory info +; ES:CX--> EXT_INFO buffer is filled with extended info +; +; If partially found the path, +; DS:SI--> '\' after the matching directory name +; ES:DI--> DIR_INFO buffer is filled with directory info +; ES:CX--> EXT_INFO buffer is filled with extended info +; +; If the Name_cache tree is empty, i.e.,no root directory name, +; DS:SI--> '\' after ':' +; ES:DI--> DIR_INFO buffer is undetermined +; ES:CX--> EXT_INFO buffer is undetermined +; +;============================================================================== + +LOOKUP PROC FAR + + mov cs:func_cod,al ; save function code + cmp From_Delete, 0 ;call from DELETE function ?? + je Look_Pack_Dir ;no, dont restore DS + mov DS,bx ;yes, restore DS + ASSUME DS:Cseg_Init + jmp short Look_save_regs ;save registers + +Look_Pack_Dir: + CALL PACK_DIR_NAME ;on return drive letter => DL, + + CALL FIND_DRIVE_CACHE_HEADER ;find drive header address + ;on return ES:BP-->drive header + jnc look_save_regs ;drive buffer found + jmp lookup_error ;drive buffer not found + +Look_Save_Regs: + push es + push di + push cx + mov ax, cs:Open_Name_Cache_Seg ;AN000; + mov es, ax ;ES = Name_Cache_Seg ;AN000; + ASSUME es:Cseg_Init ;AN000; + CALL SET_LRU ;set the Real LRU, if any. + + or cs:Flag,Is_drive_head ;level of the tree. Drive header + mov cs:Matching_Node, -1 ;Nothing found yet. + mov cs:Current_Drive, BP ;drive header + mov cs:Level, 0 ;path level is 0 + +Lookup_Path: + mov cs:Current_Node, BP ;save current node address + mov cs:Current_Sibling,0fffeh ;set no sibligs yet. + mov cs:Old_SI, si ;save current path address + + CALL PACK_DIR_NAME ;get the next dir name from the path + jc Lookup_Done ;yes, found the whole path. + + test cs:Flag, Is_drive_head ;dir name = drive header ? + jz Lp_Path1 ;no- + + push ds ;yes-drive header + mov ds,cs:Open_Name_Cache_Seg + ASSUME ds:Cseg_Init + mov BP, DS:[BP.DCH_Child_ptr] ;BP-->first child node under drive hdr + pop ds + ASSUME ds:nothing + jmp short Lp_Path2 + +Lp_Path1: + mov BP, ES:[BP.nChild_ptr] ;BP--> child of current node + +Lp_Path2: + cmp BP, -1 ;no child? + je Lookup_Done ;Not found or partially found + mov cs:Current_Node, BP ;current_node = found node + and cs:Flag, Not_drive_head ;reset the flag. + +Lp_Cmpare: + CALL CMPARE ;look for path in current node + je Lookup_Found ;Yes, found a match. Next level for + ;possible remianing path + + mov BP, ES:[BP.nSibling_ptr] ;not found. Any siblings? + mov cs:Current_Sibling,BP + cmp BP, -1 ;any more sibling? + je Lookup_Done ;no - done + + mov cs:Current_Node, BP ;yes- make the found sibling as a current + jmp short Lp_Cmpare ;node and search path in this node + +Lookup_Found: + inc cs:Level + mov cs:Matching_Node,BP ;Used by Unfold_Name_Record + + CALL PRE_LRU_STACK ;set the TEMP_LRU_Stack + jmp Lookup_Path ;continue to the next dir + +Lookup_Done: + mov si, cs:Old_SI + pop cx ;restore Extended_Info buffer + pop di ;restore Dir_Info buffer + pop es ;the segment for the above buffers + + cmp ax, -1 + je Lookup_ERR ;error occured in Pack_Dir_Name. + clc ;clear carry. + jmp short Lookup_Done1 + +Lookup_ERR: ;error exit + stc + +Lookup_Done1: + test cs:Flag, is_delete ;called by delete? + jnz Lookup_Return + jc Lookup_Exit ;If it was an error, don't change the carry flag + + CALL UNFOLD_NAME_RECORD ;unfold the current node's record +Lookup_Exit: + jmp short Lookup_Return ;return to DOS. + +Lookup_Error: ;error exit + stc + mov ax,-1 + +Lookup_Return: ;return to Delete routine. + CALL Check_It ;check tree structure + ret + +LOOKUP ENDP + + + + + +;============================================================================== +;SUBROUTINE: INSERT +; +;INPUT: DS:DI -> Dir_Info in DOS +; ES:BX -> Fastopen_Extended_Info in DOS +; Current_Node, Current_Sibling, Current_Drive, Flag +; +;OUTPUT: Information inserted into Name_cache_tree. +; +; Any Sequential Insert operation should be preceded by a Look_up +; operation. For ex., if the DOS wants to insert C:\DIR1\DIR2\File1 +; and suppose there is no matching name cache record for DIR1 in the tree. +; Firstly DOS will try to look up C:\DIR1\DIR2\File1. FASTOPEN will +; return to DOS with DS:SI points to "\" after the drive letter. +; Then, DOS will simply ask an insert operation with DS:DI, ES:BX +; points to the information on "DIR1". FASTOPEN will insert DIR1 +; onto the tree. After that DOS will ask another insert +; operation for DIR2. FASTOPEN will insert DIR2. Finally DOS will +; ask to insert File1. +; +; Suppose when DOS try to look up C:\DIR1\DIR2\File2 at this moment. +; FASTOPEN will return to DOS with DS:SI points to "\" after DIR2 (since +; DIR2 information is already in the name cache tree). Then DOS will ask +; to insert File2. +; +; Any Insert operation of subdirectory name which is deeper than (Number_ +; of_Entries - 1) will not be inserted but will just return. +; Also, for the safety reason, if the would be freed node (=LRU node) is +; the same as the Current_Node, there will be no insertion. (This is a simple +; safety valve. A more smart logic can look for the next **legitimately +; available** LRU node to use, or sometimes, simply replace the contents of the +; entry if adequate. But this will increase the complexity greatly, and I +; think the current logic is still practical enough to use despite of the +; possible small window of performance degradation in a very special cases. J.K.) +; +;============================================================================== + +INSERT PROC FAR + mov cs:func_cod,al ; save function code + inc cs:Level ;increment directory level + xor ax,ax + mov al, cs:Level + inc al + mov bp, cs:Current_Drive ;BP-->address of current drive header + push ds + mov ds,cs:Open_Name_Cache_Seg ;DS=name cache segment + + ASSUME ds:Cseg_Init ;AN000; + cmp ax, ds:[bp.DCH_Num_Entries] ;Level > (Num_Entries - 1) ? + pop ds + ASSUME ds:nothing + jbe Insert_it ;no- insert it + jmp short Insert_return ;yes return + +Insert_it: + or cs:Flag, is_insert + + CALL GET_FREE_NODE ;AX = offset value of the available + ;name_record in Name_Cache_Seg. + jc I_Exit ;Current node = would-be freed node. + + CALL MAKE_NAME_RECORD ;Fill the above name record entry. + ;ES was changed to Name_Cache_Seg. + + mov bp, cs:Current_Node ;set BP to current_node + mov bx, bp ;save it into bx + cmp cs:Current_Sibling,0fffeh ;current node sibling node ?? + je I_Child ;no-child of preceding node + mov es:[bp.nSibling_ptr], ax ;yes-make new node sibling of + jmp short I_Done ;current node + +I_Child: ;set nChild_ptr + test cs:Flag,Is_drive_head ;drive level? + jnz I_Child_first ;Yes, must be the first child + mov es:[bp.nChild_ptr], ax ;no-make ndew node child of + jmp short I_Done ;current node + +I_Child_first: ;this is the first child in this drive. + push ds + mov ds,cs:Open_Name_Cache_Seg ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov ds:[bp.DCH_Child_ptr],ax ;make new node 1st child current drive + pop ds + ASSUME ds:nothing + mov bx, cs:Current_Drive ;change bx to Current_Drive + and cs:Flag, Not_drive_head ;reset the flag + +I_Done: + mov bp, ax + mov es:[bp.nBackward_ptr],bx ;set the backward ptr of the inserted node. + + CALL PRE_LRU_STACK ;save this inserted record temporarily. + + mov cs:Current_Node,bp ;make new node current node + ;any subsequent insert operation + mov cs:Current_Sibling,0fffeh ;should be installed as a child + +I_Exit: + and cs:Flag, not_insert ;set not insert flag + +Insert_return: + CALL Check_It ;check tree structure + ret ;return + +INSERT ENDP + + + + + + +;============================================================================== +;Subroutine: DELETE +; +;INPUT: DS:SI -> path +; ES:BP -> drive_cache_header (for Look_Up operation) +; +;OUTPUT: if found, then remove the matching Name_Record will be removed from +; the tree and from the LRU chain. The freed entry will be placed +; on top of the LRU chain. +; +;============================================================================== + +DELETE PROC FAR + + mov cs:func_cod,al ; save function code + CALL PACK_DIR_NAME ;drive letter => DL, ;AN000; + + CALL FIND_DRIVE_CACHE_HEADER ;find drive header address + ;on return ES:BP-->drive header + jc d_err_exit ;error exit + + or cs:Flag, is_delete ;set the flag for Look_up. + push ds ;save DS in BX since it is going to be + pop bx ;changed for jumping to other segment + push ds + mov ax,cseg_Main + mov ds,ax ;DS=Main segment ID + assume ds:Cseg_Main + mov cs:From_Delete, 1 ;set flag indicate that the call + ;is from DELETE function + CALL VECTOR_LOOKUP ;FAR call to Lookup function + + mov cs:From_Delete, 0 ;reset from delete flag + pop ds + ASSUME ds:nothing + jc D_err_Exit ;indirectly in the same segment + + cmp byte ptr ds:[si], 0 ;found the whole path? + jne D_err_Exit ;No. + +;At this point, Current_Node = BP. + mov bx, cs:Open_Name_Cache_Seg + mov es, bx ;set ES to name_cache_seg. + ASSUME es:Cseg_Init + +Delete_Node: + cmp es:[bp.nChild_ptr], -1 ;No children? + jne D_err_Exit + CALL REMOVEFROMTREE ;remove the node while maintaing the + ;integrity of the tree. + + mov es:[bp.nCmpct_Dir_Info], ' ' ;mark that this entry is free!!! + +D_LRU_MRU: + CALL REMOVEFROMLRUCHAIN ;Remove BP from the LRU,MRU chain + + mov si, cs:Current_Drive ;Now let the deleted node to be the + push ds ; LRU node + mov ds,cs:Open_Name_Cache_Seg + ASSUME ds:Cseg_Init ;AN000; + + mov bx, ds:[si.DCH_LRU_ROOT] ;es:bx -> first node + mov es:[bp.nLRU_ptr],bx ;Target.nLRU_ptr -> first node + mov es:[bx.nMRU_ptr],bp ;First_node.nMRU_ptr -> target + mov ds:[si.DCH_LRU_ROOT],bp ;LRU_ROOT -> target + mov es:[bp.nMRU_ptr],-1 + pop ds + ASSUME ds:nothing + jmp short D_Exit ;exit + +D_err_Exit: ;error exit + stc + mov ax, -1 + +D_Exit: + and cs:Flag, not_delete ;reset the flag + CALL Check_It ;check tree structure + ret ;return + +DELETE ENDP + + + + + +;============================================================================== +;Subroutine: UPDATE +; +;INPUT: If AH = 0, then update Dir_Entry area. +; ES:DI -> Dir_entry ("dir_first" is the key to search). +; DL = Logical Drive number (0 = A, 1 = B, ...). +; +; If AH = 1, then update "Fastopen_extended_info.FEI_clusnum". +; DL = Logical Drive number (0 = A, 1 = B, ...) +; CX = The value of "dir_first" to search. +; BP = new value of FEI_clusnum in the extended_info area. +; +; If AH = 2, then delete the entry. Same effect as Delete function +; except this time the keys used to delete are; +; DL = logical drive number +; CX = the value of "dir_first" to search. +; +; If AH = 3, then delete the entry. Same effect as Delete function +; except this time the keys used to delete are; +; DL = logical drive number +; DH = directory position +; DI = directory sector (low value) +; CX = directory sector (high value) +; +; +;OUT: if found, then data is updated +; else CY and AX = -1. +; +; This routine use "starting cluster number" and "drive letter" +; as a key to find the name record. Usually the reason is DOS +; does not have any "full path" information about the file when +; it has to call this routine to update the information. +; It follows the MRU chain until it finds the name record or +; until it reaches the free name record (identified by the +; Directory name starting with ' '), or until the end of +; the MRU chain. +; +;============================================================================== + +UPDATE PROC FAR + + mov cs:func_cod,al ; save function code + cmp ah, 0 ;update directory entry ? + je Update_Dir_Entry ;yes- + cmp ah, 1 ;update extended info ? + je Update_Extended_clusnum ;yes- + cmp ah, 2 ;delete based on first clus num ? + je Update_Delete ;yes- + cmp ah, 3 ;delete based directory sector ? + je Update_Delete1 ;yes- + +U_ERROR: ;no - error exit + stc + jmp short Update_Exit + +Update_Delete: ; same as delete + CALL FIND_CLUSTER_NUMBER ; find name entry using first cluster + jc U_ERROR + jmp Delete_Node ; if found, delete entry + +Update_Delete1: ; same as delete (PTR P3718 3/10/88) + CALL FIND_DIR_SECTOR ; find name entry using directory + jc U_ERROR ; sector and directory position + jmp Delete_Node ; if found, delete node + +Update_Dir_Entry: + mov cx, es:[di.dir_first] + push es ;save Dir_Info pointer ES:DI + push di + CALL FIND_CLUSTER_NUMBER + pop si ;restore Dir_Info pointer in DS:SI + pop ds + jc U_ERROR ;error-if not found + + push bp ;found the entry + pop di + add di, nCmpct_Dir_Info ;ES:DI->Name_Record.nCmpct_Dir_Info + mov cx, ODI_head_leng + REP MOVSB ;update Cmpct_dir_info head section + add si, ODI_skip_leng + mov cx, ODI_tail_leng + REP MOVSB ;update tail section + jmp short Update_Exit ;exit + +Update_Extended_clusnum: ;update extended info field + mov cs:New_FEI_clusnum,bp + CALL FIND_CLUSTER_NUMBER ;Find entry based first cluster number + jc U_ERROR + + add bp, nExtended_Info ;es:bp -> Name_record.nExtended_Info + mov bx, cs:New_FEI_clusnum + mov es:[bp.FEI_clusnum],bx + +Update_Exit: + CALL Check_It ;check tree structure + ret ;return + +UPDATE ENDP + + + + + + +;============================================================================== +;Subroutine: FP_PURGE Rest Name Cache Buffers +; +;INPUT: Main_Name_Drive_Buff - Offset to Name cache buffer +; Main_Name_Cache_Seg - Name cache seg id +; DL = Drive ID +; +;OUT: Buffer is purged +; +;============================================================================== + +FP_PURGE PROC FAR + + mov si,Open_Name_Drive_Buff ; SI-->first Name drive cache buff + mov es,Open_Name_Cache_Seg ; ES = name cache seg ID + mov bx,es:[si].DCH_Name_Buff ; BX-->Name cache buffer + inc dl ; DL=drive number + add dl,040H ; convert drive num to drive letter + +; Search for the name drive header corresponds to the drive letter +Purge_Drv_Loop: + cmp es:[si].DCH_Drive_Letter,dl ; drive letter match ?? + je Purge_drive_cache ; yes - set drive cache + add si, size Drive_Cache_Header ; no - get address of next drive cache + jmp purge_drv_loop ; try next name drive header + +Purge_Drive_Cache: ; SI-->drive header + mov bx,es:[si].DCH_Name_Buff ; BX-->Name cache buffer + mov cx,es:[si].DCH_num_entries ; get number of name records + mov ax,bx ; save last name record address + mov es:[bx].nMRU_ptr, -1 ; make first MRU -1 + jmp short set_start + +Set_Up_Names: + mov es:[bx].nMRU_ptr,ax ;save last name record as MRU entry + add ax, size Name_Record ;AX = last name record = current name record + +Set_Start: + mov es:[bx].nChild_ptr, -1 ;no children or siblings + mov es:[bx].nsibling_ptr, -1 ;right now + mov es:[bx].nBackward_ptr, -1 + + push di + push ax + mov ax, ' ' ;AX = ' ' + mov di, bx ;DI-->current name record + add di, nCmpct_Dir_Info ;blank out the Dir name area + stosb ;in the name record + stosw + stosw + stosw + stosw + stosw + pop ax ; AX = last name record address + pop di + + dec cx ;update record count + jcxz purge_exit ;exit if last name record is done + mov dx,bx + add dx, size Name_Record ;DX-->next name record + mov es:[bx].nLRU_ptr,dx ;set LRU pointer - next name record + add bx, size Name_Record + jmp set_up_names ;set next name record + +Purge_exit: + clc + ret + +FP_PURGE ENDP + + + +;---------------------------------------------------------------------------- +; FASTOPEN SUPPORT ROUTINES +;---------------------------------------------------------------------------- +; +; PROCEDURE: Find_Drive_Cache_Header +; +; Function: Validate drive ID and find address of drive cache header +; +;IN: DL - drive letter +; Drive_Header_Start ;label +; Flag. +; +;OUT: If CY = 0 Drive Header found +; ES:BP -> Drive_Cache_Header, +; +; If CY = 1 Drive Header not found +; +;---------------------------------------------------------------------------- + +FIND_DRIVE_CACHE_HEADER PROC NEAR + + mov bp, cs:Open_name_drive_buff + push ds + mov ds,cs:Open_Name_Cache_Seg ;AN000; + ASSUME ds:Cseg_Init ;DS:BP-->first drive header ;AN000; + +FDCH_while: + cmp byte ptr ds:[bp.DCH_Drive_Letter], dl ; drive letter match + jne fdch_chk_end ; no - check next header + clc ; yes - exit + jmp short FDCH_Exit + +FDCH_Chk_End: + cmp byte ptr ds:[bp.DCH_Sibling_ptr], -1 ; is this last header ? + je FDCH_Not_Found ; yes - header not found + add bp, size Drive_Cache_Header ; no - get next header + jmp short FDCH_while ; look for match + +FDCH_Not_Found: + stc ;not found + +FDCH_Exit: ;ES:BP-->header if found + pop ds + ASSUME ds:nothing ;return + ret + +FIND_DRIVE_CACHE_HEADER endp + + + + +;---------------------------------------------------------------------- +; PROCEDURE: GET_FREE_NODE +; +; called by Insert. The LRU node pointed DCH_LRU_ROOT is returned in AX +; and DCH_LRU_ROOT points to the following node in LRU chain. +; If the node is not an empty node, then it will be removed from the +; tree. +; +; IN: Current_Drive, Current_Node +; +; OUT: AX = offset of the free node in Name_Cache_Seg +; Other registers saved. +;---------------------------------------------------------------------- + +GET_FREE_NODE PROC NEAR + + push es ;save registers + push di + push si + push bp + + mov ax, cs:Open_Name_Cache_Seg ;AN000; + mov es, ax ;ES=Name cache segment ;AN000; + ASSUME es:Cseg_Init ;AN000; + mov si, cs:Current_Drive ;SI-->drive_cache_header + push ds + mov ds,cs:Open_Name_Cache_Seg + ASSUME ds:Cseg_Init + mov ax, ds:[si.DCH_LRU_ROOT] ;get the LRU node + pop ds + ASSUME ds:nothing + + cmp ax, cs:current_Node ;LRU node=Current Node ?? + je GFN_skip ;yes- + + mov bp, ax ;BP=Current node + mov di, es:[bp.nLRU_ptr] ;DI= current LRU node's following node + mov es:[di.nMRU_ptr],-1 ;set that node's MRU ptr + push ds + mov ds,cs:Open_Name_Cache_Seg ;DS=Name cache segment + ASSUME ds:Cseg_Init + mov ds:[si.DCH_LRU_ROOT],di ;connect previous node to + pop ds ;next node + ASSUME ds:nothing + + cmp byte ptr es:[bp.nCmpct_Dir_Info],' ';an empty node? + je GFN_OK ;then no problem. + + CALL RemoveFromTree ;otherwise, it should be removed + ;from the tree. +GFN_OK: + clc + jmp short GFN_ret + +GFN_Skip: + stc + +GFN_ret: + pop bp + pop si + pop di + pop es + ret ;return + +GET_FREE_NODE endp + + + + +; +;---------------------------------------------------------------------- +; PROCEDURE: PRE_LRU_STACK +; +; When called by Look_up, Insert routine, the requested target node (BP) +; will be temporarily removed from LRU,MRU chain (until SET_LRU routine +; call), and will be pushed into a logical stack. Actually, this routine +; will not use a stack, but try to get the effect of the use of stack +; to keep the history of target nodes in "REVERSE" LRU order as follows; +; { inc Depth; +; if Depth == 1 then Bottom = BP; +; Bottom.LRU_ptr = -1; +; Bottom.MRU_ptr = -1; +; else if Depth == 2 then Top = BP; +; Top.LRU_ptr = Bottom; +; Bottom.MRU_ptr = Top; +; Top.MRU_ptr = -1; +; else if Depth >= 3 then Temp = Top; +; Top = BP; +; Top.LRU_ptr = Temp; +; Temp.MRU_ptr = Top; +; Top.MRU_ptr = -1; +; } +; +;IN: Depth, Top, Bottom, Temp, +; Requested target node (BP) +; ES = Name_Cache_Seg +; +;OUT: Target node removed from LRU,MRU chain. +; Target node's history saved in reverse LRU order. +; If called by "Delete" routine, then will just exit. +; If called by "Insert" routine, then will not attempt +; to remove the target node. +;---------------------------------------------------------------------- + +PRE_LRU_STACK PROC NEAR + + test cs:Flag, is_delete ;invoked by Delete routine + jnz PLS_Exit + test cs:Flag, is_insert ;called by Insert routine + jnz PLS_Push + + CALL RemoveFromLRUChain ;remove BP from the chain. + +PLS_Push: + push di + + inc cs:Depth + cmp cs:Depth, 1 + jne PLS_Top + mov cs:Bottom, bp ;bottom = bp + mov es:[bp.nLRU_ptr], -1 + jmp short PLS_Done + +PLS_Top: + cmp cs:Depth, 2 + jne PLS_Temp + mov cs:Top, bp ;Top = bp + mov di, cs:bottom ;di = bottom + +PLS_com: + mov es:[bp.nLRU_ptr],di ;Top.LRU_ptr = bottom + mov es:[di.nMRU_ptr],bp ;Bottom.MRU_ptr = top + jmp short PLS_Done + +PLS_Temp: + mov di, cs:Top ;di = Top + mov cs:Temp, di ;Temp = di + mov cs:Top, bp ;Top = bp + jmp short PLS_com + +PLS_Done: + mov es:[bp.nMRU_ptr],-1 + pop di + +PLS_Exit: + ret + +PRE_LRU_STACK endp +; + + + + + +;---------------------------------------------------------------------- +;PROCEDURE: SET_LRU +; +;INPUT: Depth, Top, Bottom, Current_Drive, ES = Name_Cache_Seg +; +;OUT: If Depth == 0 then exit +; Pre_LRU_Stack procedure already maintained a reverse order LRU +; mini chain. Set_LRU will just put the top after the last node +; of the current LRU chain; +; { Get the last node of LRU chain. +; if Depth == 0 then exit; +; if Depth == 1 then Last_Node.LRU_ptr = Bottom; +; Bottom.MRU_ptr = Last_Node; +; MRU_ROOT = Bottom; +; if Depth >= 2 then Last_Node.LRU_ptr = Top; +; Top.MRU_ptr = Last_Node; +; MRU_ROOT = Bottom; +; Depth = 0; +; } +;---------------------------------------------------------------------- + +SET_LRU PROC NEAR + + cmp cs:Depth, 0 ;nothing in the stack? + je SL_Exit + + push si + push di + push bx + mov si, cs:Current_Drive ;cs:si -> Drive_Cache_Header + push ds + mov ds,cs:Open_Name_Cache_Seg ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov di, ds:[si.DCH_MRU_ROOT] ;es:di -> Last node in LRU chain + + cmp cs:Depth, 1 + jne SL_Other + + mov bx, cs:Bottom + mov es:[di.nLRU_ptr],bx ;Last_Node.LRU_ptr = Bottom + mov es:[bx.nMRU_ptr],di ;Bottom.MRU_ptr = Last_Node + mov ds:[si.DCH_MRU_ROOT],bx ;MRU_ROOT = Bottom + jmp short SL_Done + +SL_Other: ;Depth >= 2 + mov bx, cs:Top + mov es:[di.nLRU_ptr],bx + mov es:[bx.nMRU_ptr],di + mov bx, cs:Bottom + mov ds:[si.DCH_MRU_ROOT],bx + +SL_Done: + pop ds + ASSUME ds:nothing + mov cs:Depth, 0 ;reset the Depth + pop bx + pop di + pop si + +SL_Exit: + ret + +Set_LRU endp + + + + + +;---------------------------------------------------------------------- +; Procedure RemoveFromLRUChain +; +;IN: Target node (BP) to be removed +; Current_drive +; ES - Name_Cache_Seg +; +;OUT: Target node removed from the LRU,MRU chain. LRU,MRU chain +; updated. +; +;---------------------------------------------------------------------- + +RemoveFromLRUChain PROC near + + push bx + push di + push si + + mov si, cs:Current_drive ;cs:si-> Drive_cache_header + mov bx, es:[bp.nMRU_ptr] ;es:bx-> Preceding node + mov di, es:[bp.nLRU_ptr] ;es:di-> Following node + cmp bx, -1 ;Is target the first node? + je RFLC_first_node + cmp di, -1 ;Is target the last node of LRU chain? + je RFLC_last_node + mov es:[bx.nLRU_ptr],di ;Preceding.LRU_ptr->following node + mov es:[di.nMRU_ptr],bx ;Following.MRU_ptr->preceding node + jmp short RFLC_done + +RFLC_first_node: + push ds + mov ds,cs:Open_Name_Cache_Seg ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov ds:[si.DCH_LRU_ROOT],di ;LRU_ROOT-> following node + pop ds + ASSUME ds:nothing + mov es:[di.nMRU_ptr], -1 ;Following node's MRU_ptr + jmp short RFLC_done + +RFLC_last_node: + push ds + mov ds,cs:Open_Name_Cache_Seg + ASSUME ds:Cseg_Init + mov ds:[si.DCH_MRU_ROOT],bx ;MRU_ROOT-> preceding node + mov es:[bx.nLRU_ptr], -1 ;Preceding node's LRU_ptr + pop ds + ASSUME ds:nothing + +RFLC_done: + pop si + pop di + pop bx + ret + +RemoveFromLRUChain endp +; + + + +;---------------------------------------------------------------------- +; Proceure RemoveFromTree +; +;IN: BP - offset of node to be removed from the tree +; This node shoud not be a subdirectory that is not empty!!! +; ES - Name_Cache_Seg +; Current_Drive +; +;OUT: The node will be freed from the tree. +; The neighbor's Child_ptr, Sibling_ptr, Backward_ptr are adjusted +; accordingly. +; The freed node's child_ptr, sibling_ptr, backward_ptr are reset to -1. +;---------------------------------------------------------------------- + +REMOVEFROMTREE PROC NEAR + + push bx + push dx + + mov bx, es:[bp.nBackward_ptr] ;get the preceding node + mov dx, es:[bp.nSibling_ptr] ;get the sibling node + cmp bx, cs:Current_Drive + je RFT_First_Child ;bp is the first child + cmp es:[bx.nChild_ptr],bp + je RFT_Child ;bp is the child of the preceding node + mov es:[bx.nSibling_ptr],dx ;bp is the Sibling of the preceding node + ;Update the preceding node's Sibling ptr + jmp short RFT_Reset + +RFT_First_Child: + push ds + mov ds,cs:Open_Name_Cache_Seg ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov ds:[bx.DCH_Child_ptr],dx + pop ds + ASSUME ds:nothing + jmp short RFT_Reset + +RFT_Child: + mov es:[bx.nChild_ptr],dx + +RFT_Reset: ;reset the deleted node's tree pointers + mov es:[bp.nChild_ptr],-1 + mov es:[bp.nSibling_ptr],-1 + mov es:[bp.nBackward_ptr],-1 + + xchg dx,bx ;now, dx=preceding node, bx=following node + cmp bx,-1 ;end of sibling? + je RFT_ret + mov es:[bx.nBackward_ptr],dx;modify backward_ptr of the sibling node + +RFT_ret: + pop dx + pop bx + ret ;return + +REMOVEFROMTREE endp +; + + + + +;---------------------------------------------------------------------- +; Procedure CMPARE +; +;IN: Packed name +; BP = target node +; +;OUT: ZERO flag set when compare O.K. +; DI destroyed. +;---------------------------------------------------------------------- + +CMPARE PROC near + + push ds + push si + mov cx, 11 + push cs + pop ds + mov si, offset cs:Packed_Name ;ds:si -> Packed_Name + mov di,bp + add di,nCmpct_Dir_Info ;es:di -> bp.nCmpact_Dir_Info + REPE CMPSB + pop si + pop ds + ret +CMPARE endp + + + + +; +;---------------------------------------------------------------------- +; Procedure: MAKE_NAME_RECORD +; +;IN: DS:DI -> Dir_Info, ES:BX -> Extended_Info +; AX = offset of the Name_Record entry in Name_Cache_Seg. +; +;OUT: Name_Record in Name_Cache_Seg filled. +; nLRU_ptr, nChild_ptr, nSibling_ptr and nMRU_ptr are set to -1 for now. +; ES, SI, DI destroyed. ES will be Name_Cache_Seg. +;---------------------------------------------------------------------- + +MAKE_NAME_RECORD PROC NEAR + + push ds ;save DS + push ax + + push es ;save Extended_Info seg in DOS + push di + pop si ;DS:SI -> Dir_Info + mov di, cs:Open_Name_Cache_Seg ;AN000; + mov es, di ;AN000; + ASSUME es:Cseg_Init ;AN000; + mov di, ax ;ES:DI -> Name_Record + mov ax, -1 + mov es:[di.nLRU_ptr],ax ;initialize pointers + mov es:[di.nChild_ptr],ax + mov es:[di.nSibling_ptr],ax + mov es:[di.nMRU_ptr],ax + add di, nCmpct_Dir_Info ;ES:DI -> Name_Record.nCmpct_Dir_Info + mov cx, ODI_head_leng ;currently 10. + rep movsb ;Move header part + add si, ODI_skip_leng ;DS:SI -> tail part of Dir_Info + mov cx, ODI_tail_leng + REP MOVSB ;move tail part. + + pop ds ;restore Extended_Info seg in DS!!! + mov si, bx ;DS:SI -> Extended_Info + mov cx, size Fastopen_Extended_Info + rep movsb ;Move Extended_Info + pop ax + pop ds ;Restore DS + + ret ;return + +MAKE_NAME_RECORD ENDP +; + + + + +;---------------------------------------------------------------------- +; Procedure Unfold_Name_Record +; +;IN: Matching_Node, ES:DI -> Dir_Info buffer, ES:CX -> Extended_Info buffer +; +;OUT: if no matching node is found, then just return +; else Dir_Info, Extended_Info buffer are filled. +;---------------------------------------------------------------------- + +Unfold_Name_Record PROC near + + cmp cs:Matching_Node, -1 + je UNR_Exit ;just exit + push ds + push si + push di + push cx ;save extended_info addr + + mov si, cs:Open_Name_Cache_Seg ;AN000; + mov ds, si ;AN000; + ASSUME ds:Cseg_Init ;AN000; + mov si, cs:Matching_Node + add si, nCmpct_Dir_Info ;DS:SI -> Cmpct_Dir_Info + + mov cx, ODI_head_leng ;Dir_Info header length + REP MOVSB ;Cmpct_Dir_Info.CDI_file_name -> ODI_head + + add di, ODI_skip_leng ;length of Skiped part of Dir_Info + mov cx, ODI_tail_leng ;Dir_Info tail length + REP movsb ;Cmpct_Dir_Info.CDI_Time -> ODI_tail + ;At this moment, SI -> nExtended_Info + + pop di ;ES:DI -> Extended_info + push di ;save di again for cx. + mov cx, size Fastopen_Extended_Info + REP movsb + + pop cx ;restore extended_info addr + pop di + pop si + pop ds + ASSUME ds:nothing +UNR_Exit: + ret ;return + +Unfold_Name_Record endp +; + + + + +;---------------------------------------------------------------------- +; PROCEDURE: PACK DIR_NAME +; +; Parse the name off of DS:SI into Packed_Name. If called first time and +; DS:[SI+1] = ':' then it is ASSUMEd to be a drive letter and it will be +; returned in DL and SI will points to '\' after ':'. If it was a directory +; name then Packed_Name will be set and SI points to '\' or 0 after the +; parsed directory name or filename. This routine will check DS:[SI] when +; called to see if it points to '\' or 0. If it points to '\' then +; it is ASSUMEd that the user want to skip the delimiter. If it was 0, +; then this routine will set carry. So, with a given drive,path string, +; the user is going to keep calling this routine until it returns +; with carry set that tells the end. +;---------------------------------------------------------------------- + +PACK_DIR_NAME PROC NEAR + + cmp byte ptr ds:[si], 0 ;end of path ?? + jne PDN_Drive ;no-check for drive letter + stc + jmp short PDN_Exit ;yes-exit + +PDN_Drive: + cmp byte ptr ds:[si+1], ':' ;drive letter terminater? + jnz PDN_chk_skip ;no - + mov dl, byte ptr ds:[si] ;yes-set DL to the drive letter + inc si + inc si ;set SI -> '\' after ':' + jmp short PDN_Exit ;then exit + +PDN_chk_skip: + cmp byte ptr ds:[si], '\' ;delimeter? + jne PDN_Path ;no- + inc si ;yes-skip delimiter + cmp byte ptr ds:[si], 0 ;end of path ?? + jne PDN_Path ;no-pack path name + stc ;yes-In fact, the input from DOS was + mov ax, -1 ;D:\,0. FASTOPEN will treate + jmp short PDN_Exit ;this as an error. + +PDN_Path: ;pack path name + push es + push di + push ax + + push cs + pop es + mov di, offset cs:Packed_Name ;ES:DI-->pack buffer + + mov ax,' ' + STOSB ;blank out the Packed_Name + STOSW + STOSW + STOSW + STOSW + STOSW + mov di, offset cs:Packed_Name + +PDN_GetName: + LODSB ;DS:SI => AL, SI++ + cmp al,'.' + jz PDN_SetExt + or al,al + jz PDN_GetDone + cmp al,'\' + jz PDN_GetDone + STOSB + jmp short PDN_GetName + +PDN_SetExt: + mov di, offset cs:Packed_Name+8 + +PDN_GetExt: + LODSB + or al,al + jz PDN_GetDone + cmp al,'\' + jz PDN_GetDone + +PDN_StoExt: + STOSB + jmp PDN_GetExt + +PDN_GetDone: + dec si ;set SI back to the delimeter or 0. + pop ax + pop di + pop es + +PDN_Exit: + ret + +PACK_DIR_NAME endp + + + + + +;---------------------------------------------------------------------- +; PROCEDURE: FIND_CLUSTER_NUMBER +; +;IN: DL = driver # (0 = A, 1 = B,...) +; CX = The value of Dir_First in Name_Record to search. +; Search Name_Record entries to find the matching starting cluster number. +; The search uses MRU chain for efficiency. +; +;OUT: ES = Name_Cache_Seg +; BP = Name_Record +; if not found, carry bit. +; ES, BP register changed. +;---------------------------------------------------------------------- + +FIND_CLUSTER_NUMBER PROC NEAR + + push ax + push cx + push dx + add dl, 'A' ;convert to a drive letter + + CALL FIND_DRIVE_CACHE_HEADER ;ES:BP -> driver header if found + jc FCN_exit ;exit if not found + + mov dx, cx ;save the key in DX ;AN000; + mov ax, cs:Open_Name_Cache_Seg ;AN000; + mov es, ax ;AN000; + ASSUME es:Cseg_Init + + CALL SET_LRU ;clean up the LRU stack + + mov cs:Current_Drive,bp ;set Current_Drive (You should not set + ;Current_Drive before SET_LRU at any time!!! + push ds + mov ds,cs:Open_Name_Cache_Seg + ASSUME ds:Cseg_Init + mov cx, ds:[bp.DCH_Num_Entries] ;Max number to try + mov bp, ds:[bp.DCH_MRU_ROOT] ;get the start of MRU chaing + pop ds + ASSUME ds:nothing + +FCN_while: + cmp es:[bp.nCmpct_Dir_Info], ' ' ;Is it a free node ? + je FCN_not_found ;then no reason to continue search. + + cmp dx, es:[bp.nCmpct_Dir_Info.CDI_cluster] ;matching starting cluster # ? + je FCN_exit ;found it!!! + + mov bp, es:[bp.nMRU_ptr] ;next MRU entry address + cmp bp, -1 ;It was the end of MRU chain? + je FCN_not_found ;not found. End of search + LOOP FCN_while ;else compare cluster and contine... + +FCN_Not_found: + stc + +FCN_exit: + pop dx + pop cx + pop ax + ret + +FIND_CLUSTER_NUMBER ENDP + + + + +;---------------------------------------------------------------------- +; PROCEDURE: FIND_DIR_SECTOR (PTR 3718 3/10/88) +; +; Search Name_Record using directory sector and directory position +; for the name entry. +; +;IN: DL = driver # (0 = A, 1 = B,...) +; DI = Dirctory sector Low value +; CX = Dirctory sector high value +; DH = Dirctory position +; +;OUT: ES = Name_Cache_Seg +; BP = Name_Record +; if not found, carry bit. +; ES, BP register changed. +;---------------------------------------------------------------------- + +FIND_DIR_SECTOR PROC NEAR + + push ax + push cx + push dx + add dl, 'A' ;convert to a drive letter + + CALL FIND_DRIVE_CACHE_HEADER ;ES:BP -> driver header if found + jc FDIR_exit ; error if not found + + mov ax, cs:Open_Name_Cache_Seg ;AN000; + mov es, ax ;AN000; + ASSUME es:Cseg_Init + + CALL SET_LRU ;clean up the LRU stack + + mov ax,cx ; save directory sector high value + mov cs:Current_Drive,bp ;set Current_Drive (You should not set + ;Current_Drive before SET_LRU at any time!!! + push ds + mov ds,cs:Open_Name_Cache_Seg + ASSUME ds:Cseg_Init + mov cx, ds:[bp.DCH_Num_Entries] ;Max number to try + mov bp, ds:[bp.DCH_MRU_ROOT] ;get the start of MRU chaing + pop ds + ASSUME ds:nothing + +FDIR_while: + cmp es:[bp.nCmpct_Dir_Info], ' ' ;Is it a free node ? + je FDIR_NOT_FOUND ;then no reason to continue search. + + cmp di, word ptr es:[bp.nExtended_Info.FEI_dirsec] ;matching directory sector hi? + jne FDIR_Next ;check next entry + + cmp ax, word ptr es:[bp.nExtended_Info.FEI_dirsec+2] ;matching directory sector low ? + jne FDIR_Next ;check next entry + + cmp dh, es:[bp.nExtended_Info.FEI_dirpos] ;matching directory postion ? + je FDIR_Exit ;check next entry + +FDIR_Next: + mov bp, es:[bp.nMRU_ptr] ;next MRU entry address + cmp bp, -1 ;It was the end of MRU chain? + je FDIR_not_found ;not found. End of search + loop FDIR_while ;else compare cluster and contine... + +FDIR_Not_found: ; no found + stc + +FDIR_exit: + pop dx + pop cx + pop ax + ret + +FIND_DIR_SECTOR ENDP + + + + + +;-------------------------------------------------------------------------- +; Procedure: CHECK_IT Call Fastopen Tree Analyser to check the +; consistency of the Directory/File Tree strucutre. +;-------------------------------------------------------------------------- +CHECK_IT PROC NEAR + + pushf ; save all registers + push ax + push bx + push cx + push dx + push si + push di + push ds + push es + cmp cs:Chk_flag,0 ;Fastopen analyser enabled ?? + je Check_Exit ;no - exit + + mov ax,cs:Open_Name_Cache_Seg ;yes-set multiplex function call + mov es,ax + mov ah,091h ;load Multiplex ID + xor al,al + xor cx,cx + mov cl,cs:func_cod ;CL=Fastopen Function code + mov di,cs:Current_Drive ;ES:DI-->current drive header + INT 2FH ;call the analyser + +Check_Exit: + pop es ;restore all registers + pop ds + pop di + pop si + pop dx + pop cx + pop bx + pop ax + popf ;return + ret + +CHECK_IT ENDP + + + + + +; Calculate the size of the CSEG_OPEN Module in bytes + IF ($-Cseg_Open) MOD 16 ;AN000; + ORG ($-Cseg_Open)+16-(($-Cseg_Open) MOD 16) ;AN000; + ENDIF ;AN000; + +END_OPEN label word + + + + +CSEG_OPEN ends + end + \ No newline at end of file diff --git a/v4.0/src/CMD/FASTOPEN/FASTOPEN.LNK b/v4.0/src/CMD/FASTOPEN/FASTOPEN.LNK new file mode 100644 index 0000000..eb37c6e --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTOPEN.LNK @@ -0,0 +1,7 @@ +FASTOPEN.OBJ+ +FASTSEEK.OBJ+ +FASTINIT.OBJ+ +FASTP.OBJ+ +FASTSM.OBJ +FASTOPEN.EXE,/m; + \ No newline at end of file diff --git a/v4.0/src/CMD/FASTOPEN/FASTOPEN.SKL b/v4.0/src/CMD/FASTOPEN/FASTOPEN.SKL new file mode 100644 index 0000000..25c7c5e --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTOPEN.SKL @@ -0,0 +1,28 @@ +;========================================================== +; FASTOPEN MESSAGE SKELETON FILE +;========================================================== + +:util FASTOPEN ;AN000; +:class A ;System message class ;AN000; +:use 1 COMMON1 ;MSG 1 is always "Incorrect DOS Version" ;AN000; +:use 6 PARSE10 ;Invalid parameter message ;AN000; +:use 3 PARSE3 ;Invalid Switch + +:def 4 CR,LF,"FASTOPEN installed",CR,LF ;AN000; +:def 5 CR,LF,"FASTOPEN already installed",CR,LF ;AN000; +:def 7 CR,LF,"Too many drive entries",CR,LF ;AN000; +:def 8 CR,LF,"Same drive specified more than once",CR,LF ;AN000; +:def 9 CR,LF,"Invalid parameter",CR,LF ;AN000; +:def 11 CR,LF,"Invalid extent entry",CR,LF ;AN000; +:def 12 CR,LF,"Invalid number of file/directory entries",CR,LF ;AN000;;AN000; +:def 13 CR,LF,"Cannot setup expanded memory",CR,LF ;AN000;;AN000; +:def 14 CR,LF,"Expanded memory not available",CR,LF ;AN000;;AN000; +:def 15 CR,LF,"Invalid drive specification %1",CR,LF ;AN000;;AN000; +:def 16 CR,LF,"Not enough space in EMS. Low memory is used",CR,LF ;AN000; +:def 17 CR,LF,"Cannot use FASTOPEN for drive %1",CR,LF +:def 18 CR,LF,"Too many extent entries",CR,LF ;AN000; +:def 19 CR,LF,"Too many file/directory entries",CR,LF ;AN000; + +:end + +;========================================================== diff --git a/v4.0/src/CMD/FASTOPEN/FASTOPEN.TXT b/v4.0/src/CMD/FASTOPEN/FASTOPEN.TXT new file mode 100644 index 0000000..b1cf286 --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTOPEN.TXT @@ -0,0 +1,615 @@ + +.* +.pm 5 +:gdoc sec='' +:frontm +:titlep +:title.FASTOPEN UTILITY HIGH LEVEL DESIGN +:date. +:author.J. K. +:ETITLEP +:toc +:body +.DH NUM +.*.pa +&SYSDATE. +.*:H1.INTRODUCTION +.*:H1.ARCHITECTURE OVERVIEW + +:H1.FASTOPEN DESIGN +:H2.FASTOPEN UTILITY +:H3.FASTOPEN Overview +FASTOPEN is a utility that allows DOS to maintain the information about +files that have been opened. The purpose is to reduce the number of times DOS +has to look into the directory area of the disk for information on the file once +the information is stored by FASTOPEN. In real life, many application +programs, especially current database systems on the market, tend to open the +same file repeatedly and every open operation needs an access to the disk if the +information does not exist in the DOS buffer. The FASTOPEN utility will +eliminate these disk accesses, and hence will increase the efficiency of DOS +performance. + + +:H3.FASTOPEN Operational Description +Conceptually FASTOPEN itself is a database maintained by DOS. The data will +be stored and maintained in the system RAM. + +FASTOPEN is a user-installable, stay resident utility loaded by entering a +command +.fo off + 1). FASTOPEN D:{=L} ... + +where "..." means a possible repetition. + + "D:" is a drive letter for a non_removable media. + + "L" is the maxium number of files and subdirectories that can be + stored in the drive cache. The default value is 34, minimum + value, 10. The total number for all the drives is less + than 1000. + +.fo on + +:H4.Name Caching +FASTOPEN will keep the history of the accessed subdirectory and file +information in LRU fashion. The data are stored in a partial tree +structure that represents all the recently accessed files and +subdirectories of that drive. The number of entries entered by the +user, or the default number of 34, represents the maximum number of +nodes and leaves of the tree. As it suggests, the bigger the +number is, the more the efficient it will be. Currently each additional +increase of the entry will take 36 bytes, which is the fixed length of +a node. + +The number entered by the user should be bigger than the deepest nesting +of path entries in the drive. + +The operation on this name cache is similar to the operation on the +physical drive. +With the look up request, FASTOPEN will traverse the name cache tree from the +root to the bottom to find the requested path, filename. If found, then the +pointer to the file or subdirectory information packet will be returned, else FASTOPEN +will return the string pointer that points up to the matching subdirectory name. +In this case, if DOS wants to insert the rest of the subdirectory/file information +an insert operation should be requested for every subdirectory/file. FASTOPEN +will use the information from the previous Look_up operation for a sequence of Insert operations. + +At this moment, if there are any free entries left, then it will be used. +Otherwise, FASTOPEN will delete the least recently used leaf. Any node cannot +be deleted until the node becomes an empty leaf, i.e., without children. +If a file or a directory has been removed, then DOS will update the name +cache tree with the Delete request. The path, file will be looked up +first, and if found, then the corresponding entries will be free to the +free entry chain. If not found, then still it is O.K. since the matching file +entries had been removed by the LRU scheme. + + +:H3.Fastopen Interface +When installed, by the nature of the functionality, FASTOPEN becomes +a part of DOS and a private communication mechanism will be +established. +Inside DOS, vector pointers are established for FASTOPEN and will be +initialized by the call "CALLinstall" macro by the FASTOPEN initialization. +The structure of the FASTOPEN entry will look like; + +.fo off +FASTOPEN_ENTRY struc +FASTOPEN_ENTRY_SIZE dw 4 ;size of the following +FASTOPEN_NAME_CACHING dd ? +;FASTOPEN_FATCHAIN_CACHING dd ? ;not for DOS 3.3 +;NUMBER_OF_SFTS dw ? ;# of files - 3 +FASTOPEN_ENTRY ends +.fo on + +The initial vector pointer for FASTOPEN_NAME_CACHING +points to a dummy routine in DOS which simply set the carry flag and set AX to 0FFFFh. + +When FASTOPEN is installed, then this vectors table will be established to +point to the matching procedures in FASTOPEN module. + +The register AL will contain subfunction value on entry to FASTOPEN. + +.fo off +;FASTOPEN NAME CACHING Subfunctions +fastopen_name_look_up equ 1 +fastopen_name_insert equ 2 +fastopen_name_delete equ 3 +;fastopen_name_purge equ 4 ;Not for DOS 3.3 + +.fo off +1. Name Caching + + a. Look up + IN) DS:SI -> d:path + ES:DI -> DIR_INFO buffer in DOS to be filled by FASTOPEN + ES:CX -> Extended_Info buffer in DOS to be filled by FASTOPEN + OUT) + if found, DS:SI -> the last character of the path, i.e., 0. + ES:DI -> DIR INFO + ES:CX -> Extended INFO (explained in the data structure) + else if there exist the name cache for the drive, but could not + completely find the matching path, + DS:SI -> "\" following the directory that FASTOPEN can + find the match, + Will points to "\" after "d:" if no matching + root directory is found. + ES:DI -> Compct_Dir_Info of the subdirectory FASTOPEN + can find the match. + ES:CX -> the matching directory's Extended INFO + If cannot find the matching root directory entry, then + ES:DI, ES:CX are undetermined. + else carry flag set and AX = 0FFFFh. + + b. Insert + IN) DS:DI -> DIR info + ES:BX -> Extended info + + OUT) + If failed, then carry flag set and AX = 0FFFFh. + Insert operation handles only one file or subdirectory at a time. + So, usually insert operations are performed in a sequential manner. + A look up operation should be performed before any new sequential + insert operation. + FASTOPEN will keep the information of the pervious look up + operation in CURRENT_NODE. The CURRENT_NODE points to the matching + directory node of the previous Look up operation. The next insert + operation will use this CURRENT_NODE information to insert the + directory or file information. So, DOS will call only one Look_ + up operation and possibly several Insert operation to insert the + path. + + For example, suppose DOS wants to look up C:\DIR1\DIR2\FILE1 and + FASTOPEN only has the inforamtion up to C:DIR1. After the + look up operation, FASTOPEN will return with DS:SI points "\" + following C:\DIR1. + At this moment, if DOS decides to insert this information,then + it sets DS:DI to DIR_INFO, and ES:BX to EXTENDED_INFO of the + subdirectory DIR2, and will request an insert operation. + When control returned back to DOS, then it will set this time + DS:DI and ES:BX to those of FILE1, and will call an another + insert operation. + At the first insert operation, FASTOPEN automatically knows + that those informaton given by DOS belong to the child of + C:\DIR1, and will install it as a child. In the second operation, + again FASTOPEN knows that it is for the child of C:\DIR1\DIR2 + and will accordingly install the information for FILE1. + + c. Delete + IN) DS:SI -> d:path + + OUT) + If failed, then carry flag set and AX = 0FFFFh. + +.fo on + +:H3.FASTOPEN Special Considerations +FASTOPEN uses the following DOS function calls in its initialization +rouitine. No DOS or BIOS function calls are allowed inside the +main routine that is resident once installed. +:ul +:li.AH = 40h, Int 21h; Write to device for the messages, +:li.AH = 31h, Int 21h; Terminate Process and Remain Resident, +:li.AH = 48h, AH = 49h, AH = 4Ah, Int 21h; Allocate, free and +modify memory block. +:eul +:p. + +To prevent the corruption of any DOS operation, once FASTOPEN is +loaded it cannot be reloaded. + + +:H4.FASTOPEN Top Level Design + +:H5.Data Structure + +The structures of the records in FASTOPEN are: + +.fo off +NAME_record struc + LRU_pointer dw -1 + Child_pointer dw -1 + Sibling_pointer dw -1 + MRU_pointer dw -1 + Compct_Dir_info db 22 dup (?) + Extended_Info db 5 dup (?) +NAME_record ends + +Extended_Info struc +dirpos db 0 +dirsec dw 0 +clusnum dw 0 +Extended_Info ends + +Drive_cache_header struc +LRU_ROOT dw 0 ;Start of LRU chain for this Name cache +Child_ptr dw -1 ;points to the name cache +Sibling_ptr dw -1 ;points to the next drive header +MRU_ROOT dw 0 ;set to the end of LRU chain +Drive_letter db 'C' +Num_Entries dw 0 +Name_Cache_start dw 0 ;Start of name cache for this drive +Drive_cache_header ends + +Cmpct_Dir_Info struc +CD_File_name db 11 dup (0) +CD_File_attr db ? +CD_time dw ? +CD_date dw ? +CD_cluster dw ? +CD_Filesize dd ? +Cmpct_Dir_Info ends + +Dir_Info struc ;= full directory entry information. +DI_head db 12 dup (?) +DI_skip db 10 dup (0) ;reserved area. All the time 0. +DI_tail db 10 dup (?) +Dir_Info ends + +.fo + + +:H5.FASTOPEN Hierarch +:H6.FASTOPEN Components + +.fo off + + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + ³ FASTOPEN ³ + ÀÄÄÄÄÄÄÂÄÄÄÄÄÄÄÙ + ³ + ³ + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + ³ ³ + V V +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ INIT ³ ³ MAIN ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÂÄÄÄÄÄÄÄÙ + ³ + V + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + ³ ³ + ³ LOOK_UP, INSERT, DELETE, INIT_TREE ³ + ³ ³ + ³ (SUPPORTING MODULES) ³ + ³ ³ + ³ GET_FREE_NODE, PRE_LRU_STACK, ³ + ³ SET_LRU, MAKE_NAME_RECORD, ³ + ³ UNFOLD_NAME_RECORD, PACK_DIR_NAME, ³ + ³ REMOVEFROMLRUCHAIN ³ + ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + +.fo + +:H6.FASTOPEN Memory Structure + +.fo off + Lo_memory ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÄÂÄ + ³ LOOK_UP, ³ ³ + ³ INSERT, ³ M + ³ DELETE, ³ A + ³ & Supporting Routines ³ I + ³ ³ N + ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ + ³ INIT_TREE ³ ³ + ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ÄÅÄ + ³ DRIVE_CACHE_HEADER ³ I + ³ (After Init, this ³ N + ³ area will be used ³ I + ³ for name caches.) ³ T + ³ SHOW_ERR_MESSAGE ³ ³ + ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÄÁÄ + + High_memory +.fo + +.pa +:H5.FASTOPEN Component Interfaces + +.fo off +;************************************************************************* +; +;SUBROUTINE: INIT +; +;INPUT: +; +;OUTPUT: +; +;DESCRIPTION: +; +; 1:(Installation check) +; { Get the entry pointer of FASTOPEN from DOS. +; Check the signature ($FASTOPEN01$) +; If already installed, +; then Show 'FASTOPEN already installed'; Exit +; } +; +; 2:(Parse the command line) +; Input: User input +; +; Output: Total_Entry_Num. +; Drive_Cache_Headers set. +; End_Cache_Header. +; +; { For every drive entered +; { Drive sanity check; +; Get_Num; +; if success and Total_Entry_Num < 1000, then +; Set Drive_Cache_Header; +; } +; } +; +; 3:(Check the system memory) - Check if the system has enough +; memory for the Name caches. +; Name cache will start from the +; End_Cache_Header. +; +; Input: Total_Entry_Num, End_Cache_Header, End_Init, +; Output: End_Caches +; { +; Needed_space = size of (Name_Record) * Total_Entry_Num; +; Needed_space = Needed_space - (End_Init - End_Cache_Header); +; Free allocated memory from End_Init (AH = 4Ah); +; Set memory block from End_Init to Needed_Space (AH = 48h); +; if fail, Show 'Insufficient memory for FASTOPEN cache'; +; Set End_Caches; +; } +; +; 4: jmp to INIT_TREE +; +;************************************************************************* + + +.pa +.fo off +;************************************************************************* +; +;SUBROUTINE: INIT_TREE +; +;INPUT: Drive_cache_header, End_Caches +; +;OUTPUT:Name_cache entries installed for every drive requested. +; LRU chain established for every drive. +; FASTOPEN entry pointer set in DOS. +; Terminate & stay resident. (Up to End_Caches) +; +;DESCRIPTION: +; +; 1:(Install_Name_Cache) +; Input: Drive cache header, End_cache_header (= Name cache start) +; Output:According to the information in the header, +; the name cache entries will be established. +; Also, LRU chain, MRU_pointer are established. +; +; { Buffer_start = End_cache_header; +; For every drive header +; { LRU_ROOT = Buffer_start; +; For (i=1;i=Num_Entries;i++) +; { MRU_pointer = Buffer_start; +; Buffer_start= Buffer_start + size_of (Name_record); +; if i = Num_Entries then LRU_pointer = -1 +; else LRU_pointer = Buffer_start; +; } +; } +; } +; +; 2:(Set FASTOPEN entry pointer in DOS) +; Use CALL INSTALL macro. +; +; 3: Terminate and stay resident up to Buffer_start; +; +;************************************************************************* + + +.pa +.fo off +;************************************************************************* +; +;SUBROUTINE: MAIN +; +;INPUT: Called by DOS throught Look_up, Insert, Delete requests. +; +;OUTPUT:Request performed based on LRU scheme. +; CX, DX, DS, ES, BP value saved. Other register are destroyed. +; +;DESCRIPTION: +; Call Pack_Dir_Name ;get the drive letter in BL +; Call Get_Drive_Cache_Header ;find the matching drive header +; if not found, then AX = 0ffffh, Carry set +; else if AL = Look_up then Call Look_up +; else if AL = Insert then Call Insert +; else if AL = Delete then Call Delete +; else AX = 0ffffh, Carry set. +; +; MAJOR SUBROUTINES: +; (Look_up) - Refer to Look_up subroutine. +; (Delete) - Refer to Delete subroutine. +; (Insert) - Refer to Insert subroutine. +; +; SUPPORTING SUBROUTINES: +; 1:(Get_Free_Node) - Get the entry from the LRU_ROOT, +; Set LRU_ROOT to the next entry of the +; LRU chain +; Input: none +; Output:Entry address. LRU_ROOT updated to the next entry. +; +; 2:(Pre_LRU_Stack) - This is needed to implement LRU scheme in +; a tree structure. Since the order of traversing a tree is +; from the root to bottom and from left to right, the direct +; implementation of LRU will result the parent the least mostly +; used one instead of the child. This is exactly in the reverse +; order to what had been expected. This procedure will +; solve this problem without loss of any efficiency. In the +; Look_up operation and found the match, the found entris will +; be saved with each of its LRU, MRU pointer modified to reflect +; the desired LRU order. +; These created mini LRU chain will be attached to the +; LRU chain again by SET_LRU. SET_LRU and PRE_LRU_STACK +; should work in a synchronized fashion. SET_LRU routine +; will be called in the beginning of every Look_up, Insert +; operation. PRE_LRU_Stack will be called whenever a matching +; entry is found in a Look_up operation, or whenever a new +; entry is inserted by the Insert operation. +; Input: Current_Drive,Target node. +; Output:Depth, Top, Bottom set +; +; 3:(SET_LRU) +; Input: Depth, Top, Bottom, Current_Drive +; Output:Mini LRU chain created by Pre_LRU_Stack will be +; placed at the end of LRU chain. +; +; 4:(MAKE_NAME_RECORD) - At Insert time, BOS will give +; two types of information. DS:DI -> Dir_Info, ES:BX -> Extended_ +; Info. The Name_Record is composed of Cmpct_Dir_Info and +; Extend_Info. MAKE_NAME_RECORD will simply make a Name_Record +; from the informations from DOS. +; Input: Dir_Info, Extended_Info +; Output:Name_Record +; +; 5:(UNFOLD_NAME_RECORD) - Inverse function of above. When Look_up +; operation finishes, then unfold the Name_Record of the current_ +; node for DOS. If the Current_Node is a drive_cache_header, +; then will just return. +; Input: CS:Current_Node, ES, DI, BX set for the buffer +; Output:ES:DI->Dir_Info, ES:BX->Extended_Info buffer in DOS. +; +; 6:(PACK_DIR_NAME) - At Look_up or Delete operation, DS:SI points +; to the requested full path, for ex., "C:\DIR1.EXT\DIR2\FILE.EXT", +; 0. This routine is smart enough to recognize ":","\" and 0 as +; a delimeter and will parse until the next delimeter and leave +; SI to the next delimeter found. Also, if it is a drive name +; it will set SI to the "\" after ":" for consistency and +; it will set BL to the drive letter. +; The main function of this routine is "pack" the given directory +; name into 11 bytes format. PACKED_NAME will be filled with +; the result. For example, when it is called the first time, +; DL = "C" and SI will point to "\" before DIR1.EXT. +; The second time, PACKED_NAME will be filled with +; "DIR1 EXT" and SI will points to "\" before "DIR2". +; Likewize, if this routine is called the fourth time, +; FILE.EXT has been parsed and DS:SI will points to 0. +; When this routine is called again, then it will return +; with carry signaling that it has reached the end. +; The user is required to call this routine consequtively +; until it returns with carry. +; Input: +; Output: +; +;************************************************************************* + + +.pa +.fo off +;************************************************************************* +; +;SUBROUTINE: LOOK_UP +; +;INPUT: DS:SI -> path +; ES:DI -> DIR_INFO buffer in DOS to be filled by FASTOPEN +; ES:CX -> Extended_Info buffer in DOS to be filled by FASTOPEN +; CS:BP -> Matching Drive_cache_header +; +;OUTPUT:if found, DS:SI -> the last character of the path, i.e., 0. +; ES:DI -> DIR_INFO +; ES:CX -> Extended_INFO (explained in the data structure) +; else if there exist the name cache for the drive, but could not +; completely find the matching path, +; DS:SI -> "\" following the directory that FASTOPEN can +; find the match, +; Will points to "\" after "d:" if no matching +; root directory is found. +; ES:DI -> Dir_Info of the subdirectory FASTOPEN +; can find the match. +; ES:CX -> the matching directory's Extended INFO +; If cannot find the matching root directory entry, then +; ES:DI, ES:BX are undetermined. +; If the requested path is "D:\,0" then FASTOPEN will +; return with carry flag set and, AX = 0ffffh. +; else carry flag set and AX = 0FFFFh. +; +;GLOBAL VARIABLES: +; CURRENT_NODE, +; CURRENT_SIBLING, +; +;DESCRIPTION: +; Save Dir_Info, Extended_Info buffer address in DOS. +; Set ES to Name_Cache_Seg +; SET_LRU; +; 1: +; Current_Node = BP +; Current_Sibling = 0 +; PACK_DIR_NAME (from the path); +; if CX = 0, then jmp to 3 /*Found*/; +; Find_child (from the current_node); +; if not found then jmp to 3 +; 2: Compare Packed_name with Child_pointer.CD_filename +; if yes, then PRE_LRU_STACK; JMP to 1 +; else Find_Sibling;Current_sibling=Sibling_pointer +; if found a sibling, then Current_Node = Current_Sibling +; jmp to 2 +; else jmp to 3; +; 3: UNFOLD_NAME_RECORD /*for the info packet to DOS */ +; Exit +; +;************************************************************************* + + +.pa +.fo off +;************************************************************************* +; +;SUBROUTINE: INSERT +; +;INPUT: DS:DI -> DIR info +; ES:BX -> Extended info +; +;OUTPUT:Automatic insertion based on CURRENT_NODE, CURRENT_SIBLING +; If failed, then carry flag set and AX = 0FFFFh. +; Insert operation handles only one file or subdirectory at a time. +; So, usually insert operations are performed in a sequential manner. +; A look up operation should be performed before any new sequential +; insert operation. +; +;GLOBAL VARIABLES: +; CURRENT_NODE, +; CURRENT_SIBLING, +; +;DESCRIPTION: +; +; Make_Name_Record ;Make Name Record from the input +; Get_Free_Node +; Set_LRU ;(from TEMP_LRU_STACK) +; if current_sibling <> 0 (or current_sibling=0FFh) +; then Install as a sibling of Current_Node +; else Install as a child under Current_Node; +; Pre_LRU_stack ;(pre operation for LRU) +; Exit +; +;************************************************************************* + + +.pa +.fo off +;************************************************************************* +; +;SUBROUTINE: Delete +; +;INPUT: DS:SI -> d:path +; +;OUTPUT: If found, then remove the item from the Tree and from the +; LRU chain. Move that slot to the Top of the LRU chain. +; +;GLOBAL VARIABLES: +; +;DESCRIPTION: +; Look_Up +; If ds:si -> 0, then Remove that entry from Tree, LRU chain, +; Put that entry to the top of LRU chain +; else AX = 0FFFFh, Carry set, +; Exit +; +;************************************************************************* + + +.fo +:egdoc. + diff --git a/v4.0/src/CMD/FASTOPEN/FASTP.ASM b/v4.0/src/CMD/FASTOPEN/FASTP.ASM new file mode 100644 index 0000000..561417c --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTP.ASM @@ -0,0 +1,131 @@ + PAGE 90,132 ;A2 + TITLE fastp.asm - fastopen SYSTEM COMMAND LINE PARSER +;****************** START OF SPECIFICATIONS ***************************** +; MODULE NAME: fastp.asm +; +; DESCRIPTIVE NAME: Include the DOS system PARSER in the SEGMENT +; configuration expected by the modules of fastopen. +; +;FUNCTION: The common code of the DOS command line PARSER is optimized by +; the setting of certain switches that cause the conditional +; assembly of only the required portions of the common PARSER. +; +; ENTRY POINT: SYSPARSE, near +; +; INPUT: +; ES - has seg id of the SEGMENT +; that contains the input control blocks, +; defined below. +; +; DI - offset into ES of the PARMS INPUT BLOCK +; +; DS - has seg id of the SEGMENT +; that contains the DOS input COMMAND +; string, which is originally presented at 81h +; in the PSP. +; +; SI - offset into DS of the text of the DOS input COMMAND string +; as originally presented at 81H in the PSP. +; +; DX - zero +; +; CX - ordinal value, intially zero, updated on each subsequent call +; to the value returned in CX on the previous call. +; +; CS - points to the segment containing the +; INCLUDE PARSE.ASM statement +; +; DS - also points to the segment containing the INCLUDE +; PARSE.ASM statement. +; +; EXIT-NORMAL: Output registers: +; AX - return code: +; RC_No_Error equ 0 ; No error +; RC_EOL equ -1 ; End of command line +; +; DX - Offset into ES of the selected RESULT BLOCK. +; BL - terminated delimiter code +; CX - new operand ordinal +; SI - set past scanned operand +; +; EXIT-ERROR: Output registers: +; AX - return code: +; RC_Too_Many equ 1 ; Too many operands +; RC_Op_Missing equ 2 ; Required operand missing +; RC_Not_In_SW equ 3 ; Not in switch list provided +; RC_Not_In_Key equ 4 ; Not in keyword list provided +; RC_Out_Of_Range equ 6 ; Out of range specified +; RC_Not_In_Val equ 7 ; Not in value list provided +; RC_Not_In_Str equ 8 ; Not in string list provided +; RC_Syntax equ 9 ; Syntax error +; +; INTERNAL REFERENCES: +; ROUTINES: SYSPARSE:near (INCLUDEd in PARSE.ASM) +; +; DATA AREAS: none +; +; EXTERNAL REFERENCES: +; ROUTINES: none +; +; DATA AREAS: control blocks pointed to by input registers. +; +; NOTES: +; +; For LINK instructions, refer to the PROLOG of the main module, +; fastopen.asm. +; +; REVISION HISTORY: A000 Version 4.00: add PARSER, System Message Handler, +; +; COPYRIGHT: "MS DOS FASTOPEN Utility" +; "Version 4.00 (C)Copyright 1988 Microsoft " +; "Licensed Material - Property of Microsoft " +; +;PROGRAM AUTHOR: DOS 4.00 P L +; +;****************** END OF SPECIFICATIONS ***************************** + IF1 ; ;AN000; + %OUT COMPONENT=fastopen, MODULE=fastp.asm... + ENDIF ; ;AN000; +; = = = = = = = = = = = = + HEADER ; ;AN000; +; = = = = = = = = = = = = + +HEADER MACRO TEXT ;; ;AN000; +.XLIST + SUBTTL TEXT +.LIST + PAGE ;; ;AN000; + ENDM ;; ;AN000; + +; = = = = = = = = = = = = + HEADER ; ;AN000; +CSEG_INIT SEGMENT PARA PUBLIC 'CODE' ; + ASSUME CS:CSEG_INIT,DS:CSEG_INIT,ES:CSEG_INIT + + PUBLIC SYSPARSE ;SUBROUTINE ENTRY POINT ;AN000; + + +INCSW EQU 1 ;INCLUDE PSDATA.INC ;AN000; +FARSW EQU 0 ;CALL THE PARSER BY NEAR CALL +DATESW EQU 0 ;SUPPRESS DATE CHECKING ;AN000; +TIMESW EQU 0 ;SUPPRESS TIME CHECKING ;AN000; +FILESW EQU 0 ;SUPPRESS CHECKING FILE SPECIFICATION ;AN000; +CAPSW EQU 0 ;SUPPRESS FILE TABLE CAPS ;AN000; +CMPXSW EQU 1 ;SUPPRESS CHECKING COMPLEX LIST +DRVSW EQU 1 ;SUPPRESS SUPPORT OF DRIVE ONLY FORMAT +QUSSW EQU 0 ;SUPPRESS SUPPORT OF QUOTED STRING FORMAT ;AN000; +NUMSW EQU 1 ;SUPPRESS CHECKING NUMERIC VALUE +KEYSW EQU 0 ;SUPPRESS KEYWORD SUPPORT ;AN000; +SWSW EQU 1 ;DO SUPPORT SWITCHES ;AN000; +VAL1SW EQU 0 ;SUPPRESS SUPPORT OF VALUE DEFINITION 1 ;AN000; +VAL2SW EQU 0 ;SUPPRESS SUPPORT OF VALUE DEFINITION 2 ;AN000; +VAL3SW EQU 0 ;DO SUPPORT VALUE DEFINITION 3 + + + IF1 ; ;AN000; + %OUT COMPONENT=fastopen, SUBCOMPONENT=PARSE, MODULE=PARSE.ASM... + %OUT COMPONENT=fastopen, SUBCOMPONENT=PARSE, MODULE=PSDATA.INC... + ENDIF ; ;AN000; + INCLUDE PARSE.ASM ; ;AN000; +CSEG_INIT ENDS ; + END ; ;AN000; diff --git a/v4.0/src/CMD/FASTOPEN/FASTSEEK.ASM b/v4.0/src/CMD/FASTOPEN/FASTSEEK.ASM new file mode 100644 index 0000000..90b9118 --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTSEEK.ASM @@ -0,0 +1,2944 @@ + Page 84,132 ; +Title FASTOPEN + +;--------------- INCLUDE FILES ----------------- +.xcref +.xlist +debug=0 ;this is an equate only for DOSMAC.inc +INCLUDE DOSMAC.inc +.list +.cref +INCLUDE dirent.inc +INCLUDE fastsegs.inc ; Cannot declare this in DOS includes +INCLUDE fastopen.inc ; This include file also contains DOS equates + + +CSEG_MAIN SEGMENT PARA PUBLIC 'CODE' ; Cseg_Seek segment + +EXTRN VECTOR_DELETE:dword ; jump vector inside Cseg_Seek to make + ; a FAR call to FSeek Delete function within + ; the segment + +CSEG_MAIN ENDS + + +;***************************************************************************** +; ALL FastSeek functions are kept in a seperate segment. They are accessed +; by a FAR indirect call from the MAIN routine. + +; ADDRESSABILTY: DS is for accessing local data in Cseg_Seek segment +; ES is for accessing data in the extent cache buffer +; in the Cseg_Init segment +; On entry, only DS is set, ES is set to Cache segment later +;***************************************************************************** + +CSEG_SEEK SEGMENT PARA PUBLIC 'code' + assume cs:cseg_seek,ds:nothing,es:nothing,ss:nothing + +PUBLIC Seek_name_cache_seg ;AN000; +PUBLIC Seek_Num_Of_drives +PUBLIC Seek_extent_drive_Buff ;AN000; +PUBLIC Seek_Total_Ext_Count ;AN000; +PUBLIC Seek_Total_Name_Count ;AN000; +PUBLIC Seek_Name_Drive_Buff ;AN000; +PUBLIC Seek_Name_Cache_Buff ;AN000; +PUBLIC End_Seek +PUBLIC Check_Flag + ;AN000; +PUBLIC Fk_Open +PUBLIC Fk_Close ;AN000; +PUBLIC Fk_Insert ;AN000; +PUBLIC Fk_Delete +PUBLIC Fk_Lookup ;AN000; +PUBLIC Fk_Truncate +PUBLIC Fk_Purge + + +;;---------- FASTSEEK LOCAL VARIABLES --------------------- + +First_Phys_ClusNum dw 0 ; first phys clus num of file (file id) ;AN000; +Logical_ClusNum dw 0 ; logical cluster num to be searched ;AN000; +Physical_ClusNum dw 0 ; physical clus num of above logical clus num ;AN000; +Extent_buff_Ptr dw 0 ; starting offset of extent cache ;AN000; +drv_id db -1 ; drive id of last fastseek function +func_cod db 0 ; function code + +Cur_Hdr_Ptr dw 0 ; address of current header ;AN000; +Cur_Extn_Ptr dw 0 ; address of current extent ;AN000; +New_Extn_Ptr dw 0 ; address of area where new extent will be created +New_Hdr_Ptr dw 0 ; address of area where new header will be created ;AN000; +Prev_Hdr_Ptr dw 0 ; address of previous header ;AN000; +Prev_Extn_Ptr dw 0 ; address of previous extent ;AN000; + +Prev_MRU_Extn_Ptr dw 0 ; address of previous MRU extent ;AN000; +LRU_Prev_Hdr dw 0 ; address of previous hdr to the LRU header ;AN000; +LRU_Prev_Extent dw 0 ; address of previous extent to LRU extent ;AN000; +LRU_Extent dw 0 ; address of LRU extent ;AN000; +LRU_Hdr dw 0 ; address of LRU header ;AN000; + +Drive_Hdr_Ptr dw 0 ; address of drive header of current drive ;AN000; +From_FreeBuff dw 0 ; 1 = if call from Free_Buff routine ;AN000; +Hdr_Flag dw 0 ; 1 = current header is the only + ; remaining header in Queue +Extn_Flag dw 0 ; 1 = current extent is the only ;AN000;;AN000; + ; remaining extent under this header +Fully_Flag dw 0 ; 1= cluster fully found in extent ;AN000;;AN000; + ; 0= cluster partially found +Find_Flag dw 0 ; # = specifies the relative location of the new cluster ;AN000; +Open_Queue_Flag dw 0 ; 1 = if open queue is empty ;AN000; +Free_Flag dw 0 ; Free area Type: 0 - continuous ;AN000; + ; 1 - non-continuous +Queue_Type dw 0 ; Queue Type: 0 - Open Queue ;AN000; + ; 1 - Close Queue +phys_num dw 0 ; ** for queue analyser +logic_num dw 0 ; ** for queue analyser + + +; Following data area is initialized during initialization +Check_Flag dw 0 +Seek_name_cache_seg dw Cseg_Init ; Seg ID of Ccahe buffer +Seek_Num_Of_drives dw 0 ; number of drives ;AN000; +Seek_Total_Name_Count dw 0 ; total name count +Seek_Total_Ext_Count dw 0 ; total extent count +Seek_Name_Drive_Buff dw 0 ; starting address of name drive buffers ;AN000; +Seek_Name_Cache_Buff dw 0 ; starting address of name cahe buffers ;AN000; +Seek_extent_drive_Buff dw 0 ; starting address of extent ;AN000; + ; cache in the cache buffer + + + + +;------------------------------------------------------------------------------- +;------------------------------------------------------------------------------- +; PROCEDURE: FK_OPEN +; +; FUNCTION: Create and initialize a file header using the starting +; Physical Cluster number (file id) of the file. +; +; If the file header already exist in the OPEN Queue, then increase +; the file reference count by one and make the header +; MRU header. +; +; If header is not found in the OPEN Queue, then check to +; see if it exists in the CLOSE Queue. If found in the +; CLOSE Queue, move the header and the extents to the top of +; OPEN Queue and make the header MRU header. +; +; If the header is not found in both Queues, create a new +; header at the top of the OPEN Queue and initialize with the +; given first physical cluster number. +; +; If not enough space for new header in OPEN Queue, find the +; LRU header and Last Exetent in the CLOSED Queue. Delete this +; extent and use the space for the new header. If none in +; CLOSE Queue, find the LRU header and the LRU extent in the +; OPEN Queue. Delete this extent and use this space. +; +; +; INPUT: CX = First Physical Cluster Number of the file +; DL = Drive ID +; +; +; OUTPUT: Created a new file header. If header already exist, then the file +; reference count is incremented by one. +; +; ROUTINES REFERENCED: Find_File_Header, Find_Drive_Header +; +; COPYRIGHT: "MS DOS 4.00 Fastopen Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licensed Material - Property of Microsoft " +; +;------------------------------------------------------------------------------- + + +FK_OPEN PROC FAR + + push cs ; establish addressability ;AN000; + pop ds ; DS --> code segment ;AN000; + assume ds:Cseg_Seek ;AN000; + mov es, Seek_Name_Cache_Seg ; setup cache buff segment ;AN000; + assume es:Cseg_Init ; ES --> cache buffer segment ;AN000; + mov First_Phys_Clusnum,cx ; save physical cluster number ;AN000; + mov func_cod,al + +;------------------------------------------------------------------------------- +; Search for Drive header in the cache buffer using Drive ID in DL +;------------------------------------------------------------------------------- + CALL FIND_DRIVE_HEADER ; get drive buffer Header ;AN000; + ; DI-->drive header + jnc open_Search_Header ; header found - check for file header ;AN000; + jmp open_exit ; drive header not found - exit ;AN000; + +;------------------------------------------------------------------------------ +; Check if both OPEN and CLOSE Queues are empty. If empty, create a new +; file header at the top of OPEN Queue. If there are headers, search OPEN +; queue. If found, increment file count by one. If not found, check if +; the file header exists in CLOSE Queue. If found, move header to the +; top of the OPEN Queue. +;------------------------------------------------------------------------------ +Open_Search_Header: + inc es:[di].Extent_Count ; increment sequence count ( DEBUG) + mov ax,es:[di].Buff_Size ; total buffer size equal ;AN000; + cmp es:[di].Free_Size,ax ; to current free area ;AN000; + jne Search_Open_List ; yes, check OPEN and CLOSE Queues ;AN000; + ; for header + jmp Open_Make_Hdr ; no, make new header ;AN000; + + +;------------------------------------------------------------------------------ +; Search for header in the OPEN Queues. If found, increment file reference +; count by one. +;------------------------------------------------------------------------------ + +Search_Open_List: + mov cx,First_Phys_Clusnum ; CX = first phys clus number ;AN000; + mov si,es:[di].MRU_Hdr_Ptr ;AN000; + cmp si, -1 ; Any header in OPEN Queue ?? ;AN000; + je Open_Chk_Close_list ; none, check CLOSE Queue ;AN000; + + CALL FIND_FILE_HEADER ; search header in OPEN Queue ;AN000; + jc Open_chk_CLOSE_list ; if not found check in CLOSE Queue ;AN000; + +;------------------------------------------------------------------------------ +; Found in the OPEN Queue. Now, increment the file reference count by one +; and also make the header MRU header. If header found is LRU header then +; make previous header LRU header. If header is not LRU header, connect +; previous header to next header. If the header is the first header in the +; Queue, dont make it to MRU header since it is already at the top of Queue. +;------------------------------------------------------------------------------ + ; DI-->Header found + inc es:[di].FH_refer_Count ; increment file reference count ;AN000; + cmp Hdr_Flag, 1 ; current header Single header ?? ;AN000; + jne Open_Chk_Last_Hdr ; No, Check for last header ;AN000; + clc ; make sure caary is clear + jmp Open_Exit ; yes, exit ;AN000; + +Open_Chk_Last_Hdr: + cmp Hdr_Flag, 3 ; current header LRU header ?? ;AN000; + jne Open_Join_Gap ; no, close the gap ;AN000; + +Mark_Previous_Hdr: ; yes - mark previous hdr + mov si, Prev_Hdr_Ptr ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,-1 ; yes, Mark previous Hdr LRU hdr ;AN000; + +; Make current Hdr MRU header. No need to close the gap + CALL MAKE_MRU_HEADER ; move header to top of Queue ;AN000; + clc ; make sure caary is clear + jmp Open_Exit ; then EXIT ;AN000; + + +;----------------------------------------------------------------------------- +; Comes here if current header is first of many headers or in between a previous +; and next header. Make current header MRU header and close the gap. +;----------------------------------------------------------------------------- +Open_Join_Gap: + ; DI-->Current header + cmp Hdr_Flag, 2 ; current Header First Hdr in Queue ?? ;AN000; + jne Open_Make_MRU_Hdr ; no, jump ;AN000; + clc ; MAKE SURE caary is clear + jmp Open_Exit ; yes, no need to make MRU hdr, or ;AN000; + ; or close the gap + +Open_Make_MRU_Hdr: ; header is between 1st and last headers + CALL MAKE_MRU_HEADER ; move header to top of Queue ;AN000; + + clc ; make sure caary is clear + jmp Open_exit ; then EXIT ;AN000; + + +;------------------------------------------------------------------------------ +; Look for a header in the CLOSE Queue. If found, move file header and +; and extents (if any) to top of OPEN Queue. If not found in the CLOSE +; queue, create a new header at the top of OPEN queue. +;------------------------------------------------------------------------------ +Open_Chk_Close_List: + mov di,drive_Hdr_Ptr ; DI-->current drive header ;AN000; + cmp es:[di].CLOSE_Ptr,-1 ; anything in CLOSE Queue ?? ;AN000; + jne open_search_hdr ; if any, search CLOSE Queue ;AN000; + jmp open_make_hdr ; if none, make a new header ;AN000; + + +;------------------------------------------------------------------------------ +; CLOSE Queue is not empty, next search for header in the CLOSE Queue using +; starting physical cluster number of the file. +;------------------------------------------------------------------------------ +Open_Search_Hdr: ; + mov si,es:[di].Close_Ptr ; SI-->first header in the ;AN000; + ; in the CLOSE Queue ;AN000; + mov cx,First_Phys_Clusnum ; CX = first phys clus number ;AN000; + CALL FIND_FILE_HEADER ; find file header in CLOSE Queue ;AN000; + ; DI-->header found + jnc open_chk_only_hdr ; if found, check only header ;AN000; + jmp short open_make_hdr ; if not, make a new header ;AN000; + +;------------------------------------------------------------------------------ +; Found header in the CLOSE Queue. Check if the header found is the single HDR +; in the CLOSE Queue, If single header, then, mark the CLOSE Queue as empty +; before copy the this header to the OPEN Queue. +;------------------------------------------------------------------------------ +Open_Chk_only_Hdr: ; + cmp Hdr_flag, 1 ; Only Header in the CLOSE Queue?? ;AN000; + jne Open_chk_Last_header ; if not check header is LRU header ;AN000; + + mov di,Drive_Hdr_Ptr ; only header in the CLOSE Queue ;AN000; + mov es:[di].Close_Ptr,-1 ; mark CLOSE Queue as empty ;AN000; + jmp short Open_Move_Hdr ; then move header to OPEN Queue ;AN000; + +;------------------------------------------------------------------------------ +; Current header is not the only header in the CLOSE Queue. Now check if the +; current header is the LRU header in CLOSE Queue. If true, mark previous +; header as LRU header before moving it from from CLOSE Queue to OPEN queue. +;------------------------------------------------------------------------------ +Open_Chk_Last_Header: ; + cmp Hdr_Flag, 3 ; Current header last header ?? ;AN000; + jne Open_Close_gap ; no, close the gap before move it ;AN000; + ; to OPEN Queue + mov si, Prev_Hdr_Ptr ;AN000; + mov es:[si].Fh_Next_Hdr_Ptr,-1 ; yes, mark the previous hdr as last ;AN000; + jmp short open_move_Hdr ; header then move to the top of ;AN000; + ; OPEN Queue + +;------------------------------------------------------------------------------ +; Close the gap in the CLOSE Queue. +;------------------------------------------------------------------------------ +Open_Close_Gap: + mov Queue_Type, 1 ; set flag to indicate CLOSE Queue ;AN000; + CALL JOIN_PREV_TO_NEXT ; join previous header to next header ;AN000; + +;------------------------------------------------------------------------------ +; Now move the current header from CLOSE Queue to top of OPEN Queue +;------------------------------------------------------------------------------ +Open_Move_Hdr: + mov si,Cur_Hdr_Ptr ; SI-->Current header ;AN000; + mov di,drive_Hdr_Ptr ; DI-->drive header ;AN000; + +;------------------------------------------------------------------------------ +;Update the file refernce count to 1 before move header to OPEN Queue +;------------------------------------------------------------------------------ + mov es:[si].FH_Refer_Count, 1 ; set refernce count = 1 ;AN000; + mov ax,es:[di].MRU_Hdr_Ptr ; address of current MRU header ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,ax ; connect new header to the ;AN000; + ; current MRU header + mov es:[di].MRU_Hdr_Ptr,si ; make the header MRU header ;AN000; + clc ;AN000; + jmp short open_exit ; then exit. ;AN000; + +;------------------------------------------------------------------------------ +; If header is not found in both OPEN and CLOSE Queues, then make a new +; header in the next available free area and initialize the new header and +; make it MRU header (mov it to the top of the OPEN Queue). +; If no free space to create a new header, get space from CLOSE Queue. +; If none in CLOSE Queue, then get space from from OPEN Queue. See the +; Procedure (Find_Free_Buffer ) +;------------------------------------------------------------------------------ +Open_Make_Hdr: + + CALL MAKE_NEW_HEADER ; create new header ;AN000; + clc ;AN000; + +Open_exit: + CALL Check_it + ret ; return ;AN000; + +Fk_Open endp + + + + + + + +;-------------------------------------------------------------------------- +; PROCEDURE: FK_CLOSE +; +; FUNCTION: Search for the header on OPEN Queue. If the header is found, +; decrement the file reference count by one. If the resultant +; count is zero, then move the header and the extents under it +; to the CLOSE Queue. If not, make the header MRU header in the +; OPEN Queue. +; +; INPUT: DL = Drive Number +; CX = First Physical Cluster Number of the file +; +; OUTPUT: Moved the file header and the extents to the close Queue +; +; ROUTINES REFERENCED: Find_File_Header, Find_Drive_Header +; +; REVISION HISTORY: New (5/87) +; +; COPYRIGHT: "MS DOS 4.00 Fastopen Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licensed Material - Property of Microsoft " +; +;--------------------------------------------------------------------------- + +FK_CLOSE PROC FAR + ;AN000; +; Search for Drive header in the Cache buffer using Drive ID in DL + push cs ; establish addressability ;AN000; + pop ds ; DS --> code segment ;AN000; + assume ds:Cseg_Seek ;AN000; + mov es, Seek_Name_Cache_Seg ; setup cache buff segment register ;AN000; + assume es:Cseg_Init ; ES --> cache buffer segment ;AN000; + mov First_Phys_Clusnum, CX ; save phys cluster number ;AN000; + mov func_cod,al + + CALL FIND_DRIVE_HEADER ; search for drive header + ; DI-->Current drive buffer + jnc Close_search_hdr ; found, search for file header ;AN000; + clc ; MAKE SURE carry is clear + jmp Close_Exit ; not found, error ;AN000; + +;-------------------------------------------------------------------------- +; Search for file header in the OPEN Queue using given physical cluster number +;-------------------------------------------------------------------------- +Close_Search_Hdr: + inc es:[di].Extent_Count ; increment sequence coutn (DEBUG) + mov si,es:[di].MRU_Hdr_Ptr ; SI-->first header in OPEN Queue ;AN000; + mov cx,First_Phys_Clusnum ; CX = First phys clus num ;AN000; + CALL FIND_FILE_HEADER ; find the header in OPEN Queue + ; DI-->header found ;AN000; + jnc Close_Chk_Last_Hdr ; jump if header found ;AN000; + clc ; clear carry ;AN000; + jmp short close_exit ; headr not found - exit ;AN000; + +;-------------------------------------------------------------------------- +; Check if the header found is the only header in the OPEN Queue. If true +; go and decrement file reference count by one. +;-------------------------------------------------------------------------- +Close_Chk_Last_Hdr: + cmp Hdr_Flag, 1 ; Only header in the Queue ?? ;AN000; + je Dec_Ref_Count ; yes - decrement count, if count =0 ;AN000; + ; then move to the top of CLOSE Queue + cmp Hdr_Flag, 3 ; no - Last Header in the CLOSE Queue?? ;AN000; + jne Close_Join_Hdr ; no, close gap ;AN000; + mov si,Prev_Hdr_Ptr ; make the previous header LRU Hdr ;AN000; + mov es:[si].FH_Next_Hdr_Ptr, -1 ; mark previous hdr ;AN000; + jmp short Dec_Ref_Count ; decrement count and move to ;AN000; + ; CLOSE Queue + +;-------------------------------------------------------------------------- +; Connect previous header to next header to close the gap in OPEN Queue +;-------------------------------------------------------------------------- +Close_Join_Hdr: + mov si,Cur_Hdr_Ptr ; SI-->Current header + dec es:[si].FH_Refer_Count ; decrement fiel refernce count + cmp es:[si].FH_Refer_Count,0 ; count = 0 ?? + jne Close_Make_MRU ; no - make current header MRU header + + mov Queue_Type, 0 ; else set flag to indicate OPEN Queue ;AN000; + CALL JOIN_PREV_TO_NEXT ; close gap before move to CLOSE queue ;AN000; + jmp short move_to_Close_List ; move header to CLOSE queue + +;-------------------------------------------------------------------------- +; Decrement the reference count by one. If count = 0, then move the header to +; the top of CLOSE Queue. Else, dont move to CLOSE queue, since the file has +; have multiple open before. In this case make the header MRU header in the +; OPEN queue. +;-------------------------------------------------------------------------- +Dec_Ref_Count: + mov si,Cur_Hdr_Ptr ; SI-->Current header ;AN000; + dec es:[si].FH_Refer_Count ; decrement refernece count ;AN000; + cmp es:[si].FH_Refer_Count,0 ; reference count = 0 ?? ;AN000; + je Move_to_Close_List ; yes, move header to CLOSE Queue ;AN000; + +;-------------------------------------------------------------------------- +; Else, move current Header to top of OPEN Queue. Move to the top of the queue +; only if the header is not the first header in the queue. +;-------------------------------------------------------------------------- +Close_Make_MRU: + cmp Prev_Hdr_Ptr,-1 ; first header in the Queue ?? ;AN000; + je Dont_Move_To_Top ; yes, dont move to top ;AN000; + + CALL MAKE_MRU_HEADER ; move header to top of queue ;AN000; + +Dont_Move_To_Top: + clc ;AN000; + jmp short Close_Exit ; exit ;AN000; + + +;-------------------------------------------------------------------------- +; Move header to the top of the CLOSE Queue. If the header is the only header +; header in the OPEN Queue, mark OPEN Queue empty. +;-------------------------------------------------------------------------- +Move_To_Close_List: + mov si,Cur_Hdr_Ptr ; SI-->Cur_Hdr_Ptr ;AN000; + cmp hdr_flag,1 ; single header in the Queue ?? ;AN000; + jne Join_To_Close_List ; no, move header to CLOSE queue ;AN000; + mov di,Drive_Hdr_Ptr ;AN000; + mov es:[di].MRU_Hdr_Ptr, -1 ; else mark OPEN Queue empty ;AN000; + +Join_To_Close_List: + mov di,Drive_Hdr_Ptr ; DI-->current drive header ;AN000; + mov ax,es:[di].Close_Ptr ; connect current header to the ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,ax ; previous first hdr in CLOSE queue ;AN000; + mov es:[di].Close_Ptr,si ; make the current header first + ; header in the CLOSE queue + clc ;AN000; + +Close_Exit: + CALL Check_it + ret ; return ;AN000; + +FK_CLOSE ENDP + + + + + + +;------------------------------------------------------------------------ +; +; PROCEDURE: FK_DELETE +; +; FUNCTION: Delete a specific header and extents under the header +; and release the buffers to the FREE pool +; +; Search OPEN Queue for file header. If found, delete header and +; extents and release the buffer to FREE area. If not found in OPEN +; queue, search CLOSE Queue. If found, delete header and extents +; under the header and release the area to FREE area. +; +; INPUT: CX = First Physical Cluster Number of the file +; DL = drive id +; +; OUTPUT: The file header and the extents are deleted +; +; ROUTINES REFERENCED: Find_File_Header, Find_Drive_Header +; +; REVISION HISTORY: New (5/87) +; +; COPYRIGHT: "MS DOS 4.00 Fastopen Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licensed Material - Property of Microsoft " +; +;------------------------------------------------------------------------- + +FK_DELETE PROC FAR + + push cs ; establish addressability ;AN000; + pop ds ; DS --> code segment ;AN000; + assume ds:Cseg_Seek ;AN000; + mov es, Seek_Name_Cache_Seg ; setup cache buff segment register ;AN000; + assume es:Cseg_Init ; ES --> cache buffer segment ;AN000; + mov First_Phys_Clusnum,cx ; save phys cluster number ;AN000; + mov func_cod,al + +;-------------------------------------------------------------------------- +; If the delete call is from Free_Buff, then go straight to file header +; search. Else usual delete request from DOS +;-------------------------------------------------------------------------- + cmp From_FreeBuff,1 ; call from Free_Buff routine ?? + je Del_Search_Close_List ; yes - find file header in CLOSE queue + +;-------------------------------------------------------------------------- +; Search for Drive Cache buffer using Drive ID in DL +;-------------------------------------------------------------------------- + CALL FIND_DRIVE_HEADER ; get drive buffer ;AN000; + jnc Delete_search_hdr ; found, search for file header ;AN000; + jmp Delete_Exit ; not found, error ;AN000; + +;-------------------------------------------------------------------------- +; Search for a header in the OPEN Queue using given physical cluster number +;-------------------------------------------------------------------------- +Delete_Search_Hdr: + inc es:[di].Extent_Count ; ;***; + mov si,es:[di].MRU_Hdr_Ptr ; SI-->first header in the ;AN000; + ; in the OPEN queue ;AN000; + cmp si, -1 ; any header in OPEN Queue ?? ;AN000; + je Del_search_Close_list ; none, search CLOSE queue ;AN000; + mov cx,First_Phys_Clusnum ; CX = first phys clus number ;AN000; + CALL FIND_FILE_HEADER ; find the header in OPEN queue ;AN000; + jnc Del_Open_Last_Hdr ; if found, jump ;AN000; + + +;-------------------------------------------------------------------------- +; Not found in OPEN queue. Search in CLOSE queue +;-------------------------------------------------------------------------- +Del_Search_Close_List: + mov di,Drive_Hdr_Ptr ;AN000; + mov si,es:[di].Close_Ptr ; SI-->first header in the ;AN000; + ; in the CLOSE queue + cmp si, -1 ; anything in CLOSE Queue ?? ;AN000; + jne Del_scan_close_list ; yes, jump ;AN000; + clc ; none, header not found ;AN000; + jmp delete_exit ; exit ;AN000; + +Del_Scan_Close_List: + mov cx,First_Phys_Clusnum ; CX = first phys clus number ;AN000; + CALL FIND_FILE_HEADER ; find the header in CLOSE queue ;AN000; + ;AN000; + jnc Del_Close_last_hdr ; if found, chk if this header ;AN000; + ; is the last header in CLOSE queue + clc ; else, set header not found ;AN000; + jmp delete_exit ; and then exit ;AN000; + + +;------------------------------------------------------------------------- +; Header found in CLOSE queue. Check header found is the only single +; header left in the queue. +;------------------------------------------------------------------------- +Del_Close_Last_Hdr: + cmp Hdr_Flag, 1 ; Single Header in CLOSE Queue ?? ;AN000; + jne Del_Chk_LRU_Hdr ; no, check for LRU header ;AN000; + +;-------------------------------------------------------------------------- +; Yes, single header in the queue, make CLOSE_PTR empty before delete the +; header from the queue. +;-------------------------------------------------------------------------- + mov di,Drive_Hdr_Ptr ;AN000; + mov es:[di].Close_Ptr, -1 ; mark CLOSE_Ptr as empty ;AN000; + jmp short delete_Free_Buff ; release the deleted header ;AN000; + +Del_Chk_LRU_Hdr: + cmp Hdr_Flag, 3 ; Last Header in the CLOSE Queue ?? ;AN000; + jne Del_Join_Hdr ; no, close gap ;AN000; + mov si,Prev_Hdr_Ptr ; make the previous header LRU Hdr ;AN000; + mov es:[si].FH_Next_Hdr_Ptr, -1 ; mark previous hdr ;AN000; + jmp short delete_Free_Buff ; release the deleted header ;AN000; + +;-------------------------------------------------------------------------- +; Connect previous header to next header to close the gap in CLOSE Queue +;-------------------------------------------------------------------------- +Del_Join_Hdr: + mov Queue_Type, 1 ; set flag to indicate CLOSE Queue ;AN000; + CALL JOIN_PREV_TO_NEXT ; close gap ;AN000; + ;AN000; + jmp short Delete_Free_Buff ; release header to FREE area ;AN000; + + + +;------------------------------------------------------------------------- +; Header found in OPEN queue. Check header found is the only single +; header left in the queue. +;------------------------------------------------------------------------- +Del_Open_Last_Hdr: + cmp Hdr_Flag, 1 ; Single Header in OPEN Queue?? ;AN000; + jne Del_Chk_Opn_LRU_Hdr ; no, check for LRU header ;AN000; + +;-------------------------------------------------------------------------- +; Yes, single header in the queue, mark OPEN Queue empty before delete +;-------------------------------------------------------------------------- +; the header from the queue. + mov di,Drive_Hdr_Ptr ;AN000; + mov es:[di].MRU_Hdr_Ptr, -1 ; mark OPEN Queue as empty ;AN000; + jmp short delete_Free_Buff ; release the delete header ;AN000; + +Del_Chk_OPN_LRU_Hdr: + cmp Hdr_Flag, 3 ; Last Header in the CLOSE Queue ?? ;AN000; + jne Del_Opn_Join_Hdr ; no, close gap ;AN000; + mov si,Prev_Hdr_Ptr ; make the previous header LRU Hdr ;AN000; + mov es:[si].FH_Next_Hdr_Ptr, -1 ; mark previous hdr ;AN000; + jmp short Delete_Free_Buff ; release header to FREE area ;AN000; + +;-------------------------------------------------------------------------- +; Connect previous header to next header to close the gap in OPEN queue +;-------------------------------------------------------------------------- +Del_Opn_Join_Hdr: + mov Queue_Type, 0 ; set flag to indicate OPEN Queue ;AN000; + CALL JOIN_PREV_TO_NEXT ; close gap ;AN000; + ;AN000; + +;---------------------------------------------------------------------------- +; Header and extends found. Mark the beginning of this free area with "-2". +; Connect this header to the FREE area. Mark all extnts under this header +; and chain them together through the 4th word. Connect the last extent to +; the OLD free area. This process will effectively release the header to the +; FREE area. Finally update the FREE area size in the Drive header. +; +; NOTE: The deleted buffers have size same as the size of a header or extent. +; Each buffers first location contains a marker (-2) to indicate that +; the buffer is a discontinuous buffer. Each discontinuos buffer is +; connected to the next discontinuous buffer through the 4TH word. +;--------------------------------------------------------------------------- + +Delete_Free_buff: + mov di,Drive_Hdr_Ptr ; SI-->drive header ;AN000; + mov si,Cur_Hdr_Ptr ; DI-->current header ;AN000; + +;------------------------------------------------------------------------- +; Put (-2) in the beginning of the released area to indicate that this is +; a discontinuous free area. Each Free area is 8 bytes which is same size +; as an extent or header. +;------------------------------------------------------------------------- + mov ax,-2 ;AN000; + mov es:[si], ax ;AN000; + cmp es:[si].FH_Next_Extn_Ptr, -1 ; any extents under this header ?? ;AN000; + jne del_look_extent ; yes, jump ;AN000; + +;------------------------------------------------------------------------- +; There is no extents under this header. Connect relased header to the +; Free area and update Free area size in drive header before exit. +;------------------------------------------------------------------------- + mov si,Cur_Hdr_Ptr ; SI-->Current Header ;AN000; + mov di,Drive_Hdr_Ptr ; DI-->Drive Header ;AN000; + mov ax,es:[di].Free_Ptr ; connect current header ;AN000; + mov es:[si].FH_Next_Hdr_Ptr, ax ; to the Free AREA ;AN000; + mov es:[di].Free_Ptr,si ;AN000; + mov cx, SIZE File_Header ; start with file header size ;AN000; + mov di,Drive_Hdr_Ptr ;AN000; + add es:[di].Free_Size,cx ; update free area size ;AN000; + clc ; make sure caary is clear + jmp short Delete_Exit ; Then exit ;AN000; + + +;------------------------------------------------------------------------- +; Yes, one or more extents under this header. Connect the header to the +; the first extent through 4th word (FH_Next_Hdr_Ptr). Subsequent free +; extents are connected through the 4th word (EH_Next_Extn_Ptr). Next calculate +; the size of the header and possible extendta and update the free area +; size in the drive header. +;------------------------------------------------------------------------- +Del_Look_Extent: + mov si,Cur_Hdr_Ptr ; SI-->Current Header ;AN000; + mov ax, -2 ; mark header as discontinuous ;AN000; + mov es:[si],ax ; free area (12/28) ;AN000; + mov cx, SIZE File_Header ; start with file header size ;AN000; + + mov ax,es:[si].FH_Next_Extn_Ptr ; AX-->first extent under this hdr ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,ax ; connect this header to first extnt ;AN000; + ; through the 4th word ;AN000; + mov si,ax ; SI-->First extent ;AN000; + mov ax, -2 ; mark first extent as discontinous ;AN000; + mov es:[si],ax ; free area ;AN000; + +Delete_Loop: + add cx, SIZE Extent_Header ; add size of extent ;AN000; + cmp es:[si].EH_Next_Extn_Ptr, -1 ; current extent last extent ? ;AN000; + je Del_Update_Free_Size ; yes - jump (12/28) ;AN000; + mov ax,es:[si].EH_Next_Extn_Ptr ; get pointer to next extent ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,ax ; connect curr ext to next extent ;AN000; + mov si,ax ; SI-->next extent ;AN000; + mov ax, -2 ; mark subsequent extents as ;AN000; + mov es:[si],ax ; discontinuous free areas ;AN000; + jmp Delete_Loop ; adding the size until last extent ;AN000; + +Del_Update_Free_Size: + mov di,Drive_Hdr_Ptr ;AN000; + add es:[di].Free_Size,cx ; update free area in drive header ;AN000; + ;AN000; +; At this point SI-->Last extent + mov di,Drive_Hdr_Ptr ; DI-->drive header ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,ax ; connect last extent under this ;AN000; + ; header to the Free area + mov ax,Cur_Hdr_Ptr ; AX-->Current header ;AN000; + mov es:[di].Free_Ptr,ax ; connect header being deleted to ;AN000; + ; the free pool ;AN000; +Delete_Exit: + clc + cmp check_flag,0 + jne open_chk_Que + clc + ret +Open_Chk_Que: + CALL Check_it + ret ; exit ;AN000; + +FK_DELETE ENDP + + + + + + + + +;-------------------------------------------------------------------------- +; PROCEDURE: FK_INSERT +; +; FUNCTION: Search for a specific extent using the starting physical +; cluster number and the given logical cluster number. +; Insert the given physical cluster number in the extent +; indexed by the given logical cluster number. If extent is +; not found, create a new extent. If free space is not +; available, take free space free CLOSE or OPEN Queue. +; +; INPUT DL = drive number +; CX = First Physical Cluster Number of the file +; BX = Logical Cluster Number +; DI = Physical Cluster Number +; +; OUTPUT: Physical cluster number is inserted. If extent is not found, +; a new file is created +; +; ROUTINES REFERENCED: Find_File_Header, Find_Extent, Find_LRU_Header +; +; REVISION HISTORY: New (5/87) +; +;------------------------------------------------------------------------ + +FK_INSERT PROC FAR + push cs ; Establish addressability ;AN000; + pop ds ; DS --> code segment ;AN000; + assume ds:Cseg_Seek ;AN000; + mov es, Seek_Name_Cache_Seg ; setup cache buff segment register ;AN000; + assume es:Cseg_Init ; ES --> cache buffer segment ;AN000; + + mov first_phys_clusNum,cx ; save cluster numbers ;AN000; + mov Logical_ClusNum,bx ;AN000; + mov Physical_ClusNum,di ;AN000; + mov func_cod,al + +; Search for Drive Cache buffer using Drive ID in DL + CALL FIND_DRIVE_HEADER ; get drive buffer ;AN000; + jnc Insert_Search_Hdr ; found, search for file header ;AN000; + jmp Insert_Exit ; not found, error ;AN000; + +;-------------------------------------------------------------------------- +; If there are no free buffers and there is only a single header in the +; OPEN queue then there is no headers in the CLOSE queue, then the new +; clusters wont be insterted. This is because, file header should not consume +; its own extent if no free space is available. +;-------------------------------------------------------------------------- +Insert_Search_Hdr: + inc es:[di].Extent_Count ; increment sequence count (DEBUGGING) + mov si,es:[di].MRU_Hdr_Ptr ; SI-->first header in OPEN queue ;AN000; + cmp es:[si].FH_Next_Hdr_Ptr, -1 ; only one header in OPEN queue?? + je insert_chk_buff ; yes - check free buffer + jmp short insert_Inc_count ; no - go and insert clusters + +Insert_Chk_Buff: + cmp es:[di].Free_Size, 0 ; any free buffers ?? + jne Insert_Inc_Count ; yes - go insert clusters + cmp es:[di].Close_Ptr, -1 ; any headers in close queue?? (1/7/88 ;AN000; + jne Insert_Inc_Count ; yes - go insert clusters + clc ; no - dont insert clusters + jmp Insert_Exit ; exit + +insert_Inc_Count: + mov si,es:[di].MRU_Hdr_Ptr ; SI-->first header in the OPEN queue ;AN000; + mov cx,first_phys_clusnum ; CX = physical cluster number ;AN000; + CALL FIND_FILE_HEADER ; find the header in OPEN queue ;AN000; + ; DI-->Header + jc Insert_Make_Hdr ; header not found, make new header ;AN000; + jmp Insert_Find_extent ; header is found, now go and ;AN000; + ; search for the extent + +;-------------------------------------------------------------------------- +; If header not found, create a new header in the free area and connect it +; to the top of the OPEN queue. Mark the new header with no extents. Insert +; the first logical and physical cluster number into the header. At this +; point CX=First Physical Cluster number. +;-------------------------------------------------------------------------- +Insert_Make_Hdr: + CALL MAKE_NEW_HEADER ; make a new header at the top ;AN000; + ; top of the queue +;-------------------------------------------------------------------------- +; Now the header is created, next create an extent and put both logical and +; physical cluster number in the extent. The new extent should be +; created at the bottom end of the current queue, except if AX =3, +; then the new extent will be created between current and previous extent. +; Use Find_Free_Buffer to check the free space. +;-------------------------------------------------------------------------- + CALL FIND_FREE_BUFFER ; get free area for new extent ;AN000; + jnc ins_save_addrs1 ; found, jump ;AN000; + jmp Insert_Exit ; if free area found is its own ;AN000; + ; header, exit +Ins_Save_Addrs1: + mov di,Drive_Hdr_Ptr ; DI-->Drive header ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov New_Extn_Ptr,ax ; save new extent address ;AN000; + CALL UPDATE_FREE_AREA ; update Free area ;AN000; + + mov di,Drive_Hdr_Ptr ; DI-->Drive header ;AN000; + mov ax,New_Extn_Ptr ; beginning of new extent ;AN000; + mov si,Cur_Hdr_Ptr ; SI-->Current header ;AN000; + mov es:[si].FH_Next_Extn_Ptr,ax ; connect current header to adj CHAIN ;AN000; + mov es:[si].FH_MRU_EXTN_Ptr,ax ; connect current header to LRU chain ;AN000; + mov si,New_Extn_Ptr ; SI-->New extent + mov bx,Logical_ClusNum ;AN000; + mov es:[si].EH_Logic_Clus_Num,bx ; insert logical clus num ;AN000; + mov cx,Physical_ClusNum ;AN000; + mov es:[si].EH_Phys_Clus_Num,cx ; insert physical clus num ;AN000; + mov es:[si].EH_Count,0 ; set initial count = 0 ;AN000; + +;-------------------------------------------------------------------------- +; Make new extent LRU extent +;-------------------------------------------------------------------------- + mov es:[si].EH_Next_Extn_Ptr, -1 ; mark no next extent in sorted chain + mov es:[si].EH_Prev_Extn_Ptr, -1 ; mark no previous extent in sorted chain ;AN000; + mov es:[si].EH_Next_LRU_Ptr, -1 ; mark no next extent in MRU-LRU chain ;AN000; + mov es:[si].EH_Prev_LRU_Ptr, -1 ; mark no previous extent in MRU-LRU chain + clc ; + jmp Insert_Exit ; exit ;AN000; + +;-------------------------------------------------------------------------- +; Header found, Check to see any extent under this header. If not create +; new extent. If there are extents, search for the relative position of the +; given cluster number among the extents under current header. +;-------------------------------------------------------------------------- +Insert_Find_Extent: + mov di,Cur_Hdr_Ptr ; DI-->Current header + mov si,es:[di].FH_Next_Extn_Ptr ; SI-->first extent under current hdr ;AN000; + cmp si,-1 ; any extent under this header ? ;AN000; + jne Find_relative_location ; yes, Find relative location of the + ; given cluster numbers ;AN000; + +; Else create new extent under the current header. + CALL FIND_FREE_BUFFER ; get free area for new extent ;AN000; + jnc ins_save_addrs2 ; found, jump ;AN000; + jmp Insert_Exit ; else free area found is its own ;AN000; + ; header, *** ERROR **** exit +Ins_save_addrs2: + mov di,Drive_Hdr_Ptr ; DI-->Drive header ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov New_Extn_Ptr,ax ; save new extent address ;AN000; + + CALL UPDATE_FREE_AREA ; update Free area pointers ;AN000; + + mov di,Drive_Hdr_Ptr ; DI-->Drive header pointer ;AN000; + mov ax,New_Extn_Ptr ;AN000; + mov si,Cur_Hdr_Ptr ; SI-->Current header ;AN000; + mov es:[si].FH_Next_Extn_Ptr,ax ; connect new extent to header ;AN000; + mov es:[si].FH_MRU_EXTN_Ptr,ax + mov si,New_Extn_Ptr ;### next extent start in the free_ptr ;AN000; + mov bx,Logical_ClusNum ;AN000; + mov es:[si].EH_Logic_Clus_Num,bx ; insert logical ;AN000; + mov cx,Physical_ClusNum ;AN000; + mov es:[si].EH_Phys_Clus_Num,cx ; insert physical cluster numbe ;AN000; + mov es:[si].EH_Count,0 ; ;AN000; + mov es:[si].EH_Next_Extn_Ptr,-1 ; mark this extent as last extent ;AN000; + mov es:[si].EH_Next_LRU_Ptr,-1 ; ### mark this extent as last extent ;AN000; + mov es:[si].EH_Prev_Extn_Ptr,-1 ; mark there is no prev extent ;AN000; + mov es:[si].EH_Prev_LRU_Ptr,-1 ; mark there is no prev LRU extent + jmp Insert_Make_MRU ; make current header MRU header ;AN000; + + +;-------------------------------------------------------------------------- +; Check if the given cluster number will be continuous to either High or Low +; end of any extent under current header or should create a new extent +; If not, check whether a new extent for the cluster is to be created +; between current and previous extent - Current and next extent or new +; extent at the bottom of the queue. +;-------------------------------------------------------------------------- +Find_Relative_Location: + CALL FIND_CLUSTER_LOCATION ; find relative position of new extent ;AN000; + jnc chk_continuity ; position found ;AN000; + clc ; clusters already exist in an extent. + jmp Insert_exit ; return to DOS ;AN000; + +;-------------------------------------------------------------------------- +; Extent found. Check for LOW end contiguous. If true insert in the current +; extent and update the count +;-------------------------------------------------------------------------- +Chk_continuity: + cmp find_flag,1 ; LO end contiguous to current extent? ;AN000; + jne Insert_chk_HI ; no - check high end contiguous ;AN000; + mov si,Cur_Extn_Ptr ; yes - insert and update ;AN000; + mov cx,Logical_ClusNum ; save new logical and pysical ;AN000; + mov es:[si].EH_Logic_Clus_Num,cx ; cluster numbers as first clusters ;AN000; + mov cx,Physical_ClusNum + mov es:[si].EH_Phys_Clus_Num,cx ;AN000; + inc es:[si].EH_Count ; update extent range count ;AN000; + mov di,Drive_Hdr_Ptr ; DI-->drive header + cmp es:[di].Free_Ptr,0 ; any free buffer ?? + je Chk_low_MRU ; no - make current extent MRU extent + jmp Insert_Make_MRU ; yes - make current header MRU header ;AN000; + +Chk_Low_MRU: + mov Cur_Extn_Ptr, si + CALL Make_MRU_Extent ; Move extent next to current header + jmp Insert_Make_MRU ; Make current header MRU header ;AN000; + +;-------------------------------------------------------------------------- +; Check if clusters are high end contiguous to current extent. If true +; increment count and then make the extent MRU extent only if no free +; buffer is available. +;-------------------------------------------------------------------------- +Insert_Chk_HI: + cmp find_flag,2 ; HI end contiguous to current extent? ;AN000; + jne Insert_chk_between ; no, jump ;AN000; + mov si,Cur_Extn_Ptr ; SI-->Current extent ;AN000; + inc es:[si].EH_Count ; increment the cluster range count ;AN000; + mov di,Drive_Hdr_Ptr ; DI-->current drive header + cmp es:[di].Free_Ptr,0 ; any free buffers ?? + je Chk_Hi_MRU ; no - make current extent MRU extent + jmp Insert_Make_MRU ; yes - current header MRU header ;AN000; + +Chk_Hi_MRU: + mov Cur_Extn_Ptr, si ; SI -->extent to be MRU + CALL Make_MRU_Extent ; move extent next to current header + jmp Insert_Make_MRU ; Make current header MRU header ;AN000; + + +;-------------------------------------------------------------------------- +; Check to see the cluster number belongs to a new extent between current +; and Previous extent or header. If not it belongs to a new extent at the +; bottom end of the queue. +;-------------------------------------------------------------------------- +Insert_Chk_Between: + cmp find_flag,3 ; between current and previous exts?? ;AN000; + je Connect_prev_next ; yes, jump ;AN000; + + cmp find_flag,5 ; between current and next extents?? ;AN000; + jne Connect_to_end ; no, create new extent at bottom ;AN000; + ; bottom of the queue + jmp Connect_cur_next ; yes create new extent between ;AN000; + ; current and next extent + +;-------------------------------------------------------------------------- +; No, make new extent at the BOTTOM of the queue. +;-------------------------------------------------------------------------- +CONNECT_TO_END: ; At this point SI-->Last extent in queue ;AN000; + CALL FIND_FREE_BUFFER ; Check for free area ;AN000; + jnc ins_save_addrs3 ;AN000; + jmp Insert_Exit ; if free area found is its own ;AN000; + ; header, *** ERROR *** exit +Ins_Save_Addrs3: + mov di,Drive_Hdr_Ptr ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov New_Extn_Ptr,ax ; save new extent address ;AN000; + CALL UPDATE_FREE_AREA ; update Free_Ptr and Free_Size ;AN000; + + mov ax,New_Extn_Ptr ;AN000; + mov di,Cur_Extn_Ptr ; SI-->Current extent ;AN000; + cmp ax, di ; If free area got is the last + jne Use_Cur_Extent ; last extent itself then use previous extent + mov di, Prev_Extn_Ptr ; SI-->Previous extent + +Use_Cur_extent: + mov es:[di].EH_Next_Extn_Ptr,ax ; connect new extent to current or previous extent ;AN000; + mov si,New_Extn_Ptr ; next extent start in the free_ptr ;AN000; + mov es:[si].EH_Prev_Extn_Ptr, di ; set previous extent address + mov bx,Logical_ClusNum ;AN000; + mov es:[si].EH_Logic_Clus_Num,bx ; insert logical ;AN000; + mov cx,Physical_ClusNum ;AN000; + mov es:[si].EH_Phys_Clus_Num,cx ; insert physical cluster numbe ;AN000; + mov es:[si].EH_Count,0 ; initial cluster range + +; Make new extent last extent in the sorted chain + mov es:[si].EH_Next_Extn_Ptr, -1 ; mark as Last extent of the queue ;AN000; +; make the new extent MRU extent in the MRU_LRU chain + mov di,Cur_Hdr_Ptr ; DI-->Current header + mov ax,es:[di].FH_MRU_Extn_Ptr ; AX-->Previous MRU extent + mov es:[si].EH_NEXT_LRU_Ptr,ax ; connect previous to current extent + mov es:[si].EH_Prev_LRU_Ptr, -1 ; mark no previous LRU extent ;AN000; + mov es:[di].FH_MRU_Extn_Ptr,si ; make current extent MRU extent + mov di,ax + mov es:[di].EH_Prev_LRU_Ptr,si ; connect previous to current extent + jmp Insert_Make_MRU ; make current header MRU header + ;AN000; + + +;-------------------------------------------------------------------------- +; Make new extent between current and previous extents. If no previous extent +; connect the new extent to the current header. +;-------------------------------------------------------------------------- +CONNECT_PREV_NEXT: + CALL FIND_FREE_BUFFER ; get free area for new extent ;AN000; + jnc Prev_Next_Update ; found, jump ;AN000; + jmp Insert_Exit ; if free area found is its own ;AN000; + ; header, **ERROR** exit +Prev_Next_Update: + mov di,Drive_Hdr_Ptr ; DI-->Drive header ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov New_Extn_Ptr,ax ; save new extent address ;AN000; + ;AN000; + CALL UPDATE_FREE_AREA ; update Free_Ptr and Free_Size ;AN000; + + mov di,Drive_Hdr_Ptr ; DI-->Drive Header ;AN000; + cmp Prev_Extn_Ptr, -1 ; Any previous extents ?? ;AN000; + jne join_to_Prev_Extn ; yes - connect new extent to previous ;AN000; + ; extent +; No, connect new extent to header + mov si,Cur_Hdr_Ptr ; SI-->current header ;AN000; + mov di,New_Extn_Ptr ;AN000; + mov ax,es:[si].FH_Next_Extn_Ptr ; AX-->first extent under header + mov es:[di].EH_Next_Extn_Ptr,ax ; connect new extent to this extent + mov es:[si].FH_Next_Extn_Ptr, di ; connect new extent to cur hdr ;AN000; + mov es:[di].EH_Prev_Extn_Ptr, -1 ; address of previous extent (-1) since header + mov bx,Logical_Clusnum ; ;AN000; + mov es:[di].EH_Logic_Clus_Num,bx ; insert logical clus num ;AN000; + mov cx,Physical_Clusnum ;AN000; + mov es:[di].EH_Phys_Clus_Num,cx ; insert physical cluster numbe ;AN000; + mov es:[di].EH_Count,0 ; set count ;AN000; + mov si,ax ; SI-->previous MRU extent + mov es:[si].EH_Prev_Extn_Ptr,di ; set prev extent of prev MRU extent + +; Make the new extent MRU extent + mov si,Cur_Hdr_Ptr ; SI-->current header ;AN000; + mov ax,es:[si].FH_MRU_EXTN_Ptr ; AX-->MRU extent under header + mov di,New_Extn_Ptr ; SI-->current header ;AN000; + mov es:[di].EH_Next_LRU_Ptr,ax ; connect new extent to current extent + mov es:[di].EH_Prev_LRU_Ptr, -1 ; mark no previous LRU extent ;AN000; + mov es:[si].FH_MRU_Extn_Ptr,di ; connect new extent to header + mov si,ax + mov es:[si].EH_Prev_LRU_Ptr,di ; connect previous to current extent + Jmp Insert_Make_MRU ; make current header MRU hdr ;AN000; + +; Connect new extent to previous extent +Join_To_Prev_Extn: + mov si,New_Extn_Ptr ; SI-->New extent, connect new to ;AN000; + mov ax,Cur_Extn_Ptr ; connect previous extent ;AN000; + cmp si,ax ; new extent is created from + je join_set_adj ; current extent ?? + + mov si,Prev_Extn_Ptr ; no - SI-->Previous extent ;AN000; + mov ax,New_Extn_Ptr ; connect new extent to ;AN000; + mov es:[si].EH_Next_Extn_Ptr,ax ; previous extent ;AN000; + mov ax,Cur_Extn_Ptr + jmp short Join_Set_Next ; current extent + +Join_set_adj: ; yes - + mov si,Prev_Extn_Ptr ; no - SI-->Previous extent ;AN000; + mov bx,es:[si].EH_Next_Extn_Ptr ; get next extent address + mov ax,New_Extn_Ptr ; connect new extent to ;AN000; + mov es:[si].EH_Next_Extn_Ptr,ax ; previous extent ;AN000; + mov ax, bx ; extent to next extent + mov Cur_Extn_Ptr,bx ; change current extent + +Join_set_Next: ; from current extent + mov si,New_Extn_Ptr ; SI-->New extent, connect new to ;AN000; + mov es:[si].EH_Next_Extn_Ptr,ax ; current extent ;AN000; + mov bx,Logical_Clusnum ; then save cluster numbers ;AN000; + mov es:[si].EH_Logic_Clus_Num,bx ; insert logical ;AN000; + mov cx,Physical_Clusnum ;AN000; + mov es:[si].EH_Phys_Clus_Num,cx ; insert physical cluster numbe ;AN000; + mov es:[si].EH_Count,0 ; ;AN000; + mov ax, Prev_Extn_Ptr + mov es:[si].EH_Prev_Extn_Ptr,ax ; connect previous to current extent + mov di, Cur_Extn_Ptr ; setup previous extent link of + mov es:[di].EH_Prev_Extn_Ptr,si ; current extent + +; Make the new extent MRU extent + mov si,Cur_Hdr_Ptr ; SI-->current header ;AN000; + mov ax,es:[si].FH_MRU_EXTN_Ptr ; AX-->MRU extent under header + mov di,New_Extn_Ptr ; SI-->current header ;AN000; + mov es:[di].EH_Next_LRU_Ptr,ax ; connect new extent to current extent + mov es:[di].EH_Prev_LRU_Ptr, -1 ; mark no previous LRU extent ;AN000; + mov es:[si].FH_MRU_Extn_Ptr,di ; connect new extent to header + mov si,ax + mov es:[si].EH_Prev_LRU_Ptr,di ; connect previous to current extent + Jmp short Insert_Make_MRU ; make current header MRU hdr ;AN000; + + + +;-------------------------------------------------------------------------- +; Make new extent between current and next extents. If no next extent +; connect the new extent to the end of queue. +;-------------------------------------------------------------------------- +CONNECT_CUR_NEXT: + mov si,Cur_Extn_Ptr ; current extent ;AN000; + cmp es:[si].EH_Next_Extn_Ptr,-1 ; any next extent ?? ;AN000; + jne join_to_next_extn ; yes, join to next extent ;AN000; + jmp Connect_To_End ; make new extent at the bottom of ;AN000; + ; the current queue +Join_To_Next_Extn: + CALL FIND_FREE_BUFFER ; Find free area ;AN000; + jc Insert_Exit ; if free area found is its own ;AN000; + ; header, exit + mov di,Drive_Hdr_Ptr ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov New_Extn_Ptr,ax ; save new extent address ;AN000; + + CALL UPDATE_FREE_AREA ; update Free_Ptr and Free_Size ;AN000; + ;AN000; + mov si,Cur_Extn_Ptr ; SI-->Current extent + mov DX,es:[si].EH_Next_Extn_Ptr ; DI-->Next extent ;AN000; + mov ax,New_Extn_Ptr ;AN000; + mov es:[si].EH_Next_Extn_Ptr,ax ;connect new extent to cur extent ;AN000; + + mov si,New_Extn_Ptr ; SI-->New extent, connect new ext ;AN000;;AN000; + mov es:[si].EH_Next_Extn_Ptr,DX ; to next extent ;AN000; + mov ax, Cur_Extn_Ptr ; AX = address of current extent + mov es:[si].EH_Prev_Extn_Ptr, ax ; save address of previous extent + mov bx,Logical_Clusnum ; then save cluster numbers ;AN000; + mov es:[si].EH_Logic_Clus_Num,bx ; insert logical ;AN000; + mov cx,Physical_Clusnum ;AN000; + mov es:[si].EH_Phys_Clus_Num,cx ; insert physical cluster numbe ;AN000; + mov es:[si].EH_Count,0 ; set cluster range ;AN000; + mov di,DX ; setup prev extent link of the + mov es:[di].EH_Prev_Extn_Ptr,si ; next extent + +; Make the new extent MRU extent + mov si,Cur_Hdr_Ptr ; SI-->current header ;AN000; + mov ax,es:[si].FH_MRU_EXTN_Ptr ; AX-->MRU extent under header + mov di,New_Extn_Ptr ; SI-->current header ;AN000; + mov es:[di].EH_Next_LRU_Ptr,ax ; connect new extent to current extent + mov es:[di].EH_Prev_LRU_Ptr, -1 ; mark no previous LRU extent ;AN000; + mov es:[si].FH_MRU_Extn_Ptr,di ; connect new extent to header + mov si,ax + mov es:[si].EH_Prev_LRU_Ptr,di ; connect previous to current extent + + +;-------------------------------------------------------------------------- +; Make the Current header MRU header. If the header is MRU header, then +; dont make the header MRU header. +;-------------------------------------------------------------------------- +Insert_Make_MRU: + cmp Prev_Hdr_Ptr, -1 ; first header ?? ;AN000; + jne Ins_mru_hdr ; no, make MRU header ;AN000; + clc ; make sure caary is clear + jmp short insert_exit ; yes, exit ;AN000; + +Ins_MRU_Hdr: + CALL MAKE_MRU_HEADER ; move header to top of OPEN Queue ;AN000; + clc ; make sure caary is clear + +Insert_exit: + CALL Check_it ; analyse the queue (debugging) + ret ; EXIT ;AN000; + +FK_INSERT ENDP + + + + + + + + +;------------------------------------------------------------------------- +; PROCEDURE: FK_LOOKUP +; +; FUNCTION: Search through the OPEN Queue for a specific Header and +; extent. If header is not found, create a new header and +; make it MRU header. Else search for a specific extent which +; contains the logical cluster number. If the extent is not +; found, return partial information from previous extent or +; header. If extent is found, return physical cluster number +; corresponds to the given logical cluster number. +; +; INPUT: DL = drive number +; CX = First Physical Cluster Number of the file +; BX = Logical Cluster NUmber +; +; OUTPUT: If Carry = 0 Fully Found +; DI = Physical Cluster Number indexed by es:[BX] +; BX = Physical Cluster Number indexed by es:[BX-1] +; +; If Carry = 1 Partially Found +; BX = Last logical cluster number in previous extent +; DI = Last Physical Cluster Number indexed by es:[Last logic clus] +; +; If header not found, a new header will be created. In this case +; BX = First Logical Cluster number (0) +; DI = First Physical Cluster number of the header created +; +; NOTE: The clusters are fully found if the logical cluster has +; continuity to the previous logical cluster in the same +; extent or previous extent or previous header. +; +; ROUTINES REFERENCED: Find_File_Header, Find_Extent, Find_Drive_Header +; +; REVISION HISTORY: New (5/87) +; +; COPYRIGHT: "MS DOS 4.00 Fastopen Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licensed Material - Property of Microsoft " +; +;--------------------------------------------------------------- + +FK_LOOKUP PROC FAR ; on entry DS = seg ID of INIT + + push cs ; establish addressability ;AN000; + pop ds ; DS --> code segment ;AN000; + assume ds:Cseg_Seek ;AN000; + mov es, Seek_Name_Cache_Seg ; setup cache buff segment register ;AN000; + assume es:Cseg_Init ; ES --> cache buffer segment ;AN000; + mov First_Phys_Clusnum,cx ; save phys cluster number ;AN000; + mov Logical_ClusNum,bx + mov func_cod,al + +;-------------------------------------------------------------------------- +; Search for Drive header in the Cache buffer using Drive ID in DL +;-------------------------------------------------------------------------- + CALL FIND_DRIVE_HEADER ; Search for drive header ;AN000; + jnc Look_search_hdr ; found, search for file header ;AN000; + jmp Look_Exit ; not found, error ;AN000; + +;-------------------------------------------------------------------------- +; Search for a header in the OPEN Queue using given physical cluster number +;-------------------------------------------------------------------------- +Look_Search_Hdr: + inc es:[di].Extent_Count ; ;***; + mov si,es:[di].MRU_Hdr_Ptr ; SI-->first header in the ;AN000; + ; in the OPEN Queue + mov cx,First_Phys_Clusnum ; CX = Physical Cluster number ;AN000; + CALL FIND_FILE_HEADER ; find the header in CLOSE Queue + ;AN000; + jnc Look_Find_extent ; if found, find extent under this header + ; else create a new header ;AN000; +;-------------------------------------------------------------------------- +; If the header is not found, create a new header at the top of OPEN queue. +; Insert physical cluster number and set next header and first extent pointers +; Return partially found information. +;-------------------------------------------------------------------------- + pushf ; save carry set + CALL MAKE_NEW_HEADER ; Make a new header at the top of the queue ;AN000; + xor bx,bx ; BX = First Logical cluster number ;AN000; + mov di, First_Phys_Clusnum ; DI = First physical cluster number + popf ; carry should be set + jmp Look_exit ; exit ;AN000; + + +;-------------------------------------------------------------------------- +; If the header is found, next search for the extent that contains the +; logical and physical cluster numbers. DI--> current header +;-------------------------------------------------------------------------- +Look_Find_Extent: + cmp es:[di].FH_Next_Extn_Ptr,-1 ; any extent under this header ?? ;AN000; + jne look_search_extent ; yes, search for right extent ;AN000; + + xor bx,bx ; no, return partial info from header ;AN000; + mov di,es:[di].FH_Phys_Clus_Num ; DI = first phys clus num ;AN000; + push di ; ;AN000; + push bx ; BX = 1st logc clus num = 0 ;AN000; + mov fully_flag, 0 ; set partially found flag ;AN000; + jmp look_make_MRU_hdr ; move header to top of the OPEN queue ;AN000; + + +;-------------------------------------------------------------------------- +; Search for cluster numbers in extents starting from 1st extent. +;-------------------------------------------------------------------------- +Look_Search_Extent: + mov si,es:[di].FH_Next_Extn_Ptr ; SI-->first extent under curr hdr ;AN000; + mov Cur_Extn_Ptr,si ; save it ;AN000; + mov cx,Logical_ClusNum ; CX = logic clus num to search for ;AN000; + mov Prev_Extn_Ptr, -1 ; reset flags ;AN000; + mov Extn_Flag, 0 ; ;AN000; + cmp cx,es:[si].EH_Logic_Clus_Num ; 1st logic clus num in the ;AN000; + jl Look_proc_less + +Look_Loop1: + cmp cx,es:[si].EH_Logic_Clus_Num ; 1st logic clus num in the ;AN000; + ; current extent matches ?? + je Look_Proc_First ; yes, process 1st extent case ;AN000; + mov ax,es:[si].EH_Logic_Clus_Num ; else check subsequent extents + add ax,es:[si].EH_Count ; last logic clus num in cur extent ;AN000; + cmp cx,ax ; extent found in the cur extent ?? + jg Look_Next_Extn ; no,try next extent ;AN000;;AN000;;AN000; + jmp Look_Extn_within ; yes, process current extent ;AN000; + +Look_Next_Extn: ; + mov ax,es:[si].EH_Next_Extn_ptr ; get address of next extent ;AN000; + cmp ax,-1 ; is this last extent ?? ;AN000; + je Look_last_done ; yes, get partial ;AN000; + + mov Prev_Extn_Ptr,si ; save previous extent address ;AN000; + mov si,ax ;AN000; + mov Cur_Extn_Ptr,si ; save current extent address ;AN000; + cmp cx,es:[si].EH_Logic_Clus_Num ; logic clus num in cur extent ?? ;AN000; + jge Look_Loop1 ; may be!!, check it out ;AN000; + + jmp Look_Proc_Prev ; else get partial info from ;AN000; + ; previous extent +;------------------------------------------------------------------------- +; There are no further extents. In this case partially found. Return last +; logical and physical clusters of the last extent. +;------------------------------------------------------------------------- +Look_Last_Done: + mov si,Cur_Extn_Ptr ; SI-->Previous extent ;AN000; + mov bx,es:[si].EH_Logic_Clus_Num ; DI = first logic clus num ofprevext ;AN000; + mov di,es:[si].EH_Phys_Clus_Num ; BX = first logic clus num ofprevext ;AN000; + add di,es:[si].EH_Count ; DI = last phys clus number in extent ;AN000; + add bx,es:[si].EH_Count ; BX = last logic clus number in extent ;AN000; + push di ; last logical cluster number ;AN000;;AN000; + push bx ; last physical cluster number ;AN000; + mov fully_flag,0 ; partially found case ;AN000; + jmp Look_Make_MRU_Hdr ; make current header MRU header ;AN000; + + + +;-------------------------------------------------------------------------- +; Less than starting logical cluster of first extent. In this case return +; header info as partially found. +;-------------------------------------------------------------------------- +Look_Proc_Less: + xor bx,bx ; BX = logical cluster number = 0 ;AN000; + mov ax,es:[di].FH_Phys_Clus_Num ;AN000; + push ax ; first phys clus of current hdr ;AN000; + push bx ; first logic clus (0) of cur hdr ;AN000; + mov fully_flag,0 ; partially found case ;AN000; + jmp Look_Make_MRU_Hdr ; make current header MRU header ;AN000; + + + +;-------------------------------------------------------------------------- +; If first logical cluster number of the current extent matches with the given +; logical cluster number, see if previous logical cluster in previous header +; or extent is contiguous. If true, fully found. I this case return +; BX = first physical cluster of cuurent extent and DI = first physical +; cluster number of header if it is a header or last physical cluster number +; of previous extent. If this is not true, partially found case. In this case, +; return BX = last logical cluster number and DI = last physical cluster number +; from the previous extent. If no previous extent, then return DI = first +; physical cluster and BX = 0 from the header +; +; NOTE: The clusters are fully found if the logical cluster has +; continuity to the previous logical cluster in the same +; extent or previous extent or previous header. +;-------------------------------------------------------------------------- +Look_Proc_First: + mov si,Cur_Extn_Ptr ; SI-->current extent ;AN000; + mov di,Cur_Hdr_Ptr ; DI-->current header ;AN000; + cmp Prev_Extn_Ptr, -1 ; any previous extent ?? ;AN000; + jne look_get_prev_extent ; yes, get from previous extent ;AN000; + +;-------------------------------------------------------------------------- +; No, look for current header logical cluster number continuity +;-------------------------------------------------------------------------- + mov ax,es:[si].EH_Logic_Clus_Num ; AX = First physical cluster number ;AN000; + dec ax ; of current extent ;AN000; + cmp ax,0 ; continuity to first logical clus num ;AN000; + ; of current header which is (0) + jne Look_first_partial ; no, partially found ;AN000; + + +; Yes, fully found + mov bx,es:[si].EH_Phys_Clus_Num ; BX = First physical cluster number ;AN000; + ; current extent + mov ax,es:[di].FH_Phys_Clus_Num ; AX = First physical cluster number ;AN000; + ; of current header + push bx ; BX = 1st phys clus of current extent ;AN000; + push ax ; AX = 1st phys clus of prev header ;AN000; + mov fully_flag,1 ; FULLY found case ;AN000; + jmp Look_Make_MRU_Hdr ; mov cur header to top of the Queue ;AN000; + + +Look_First_Partial: + xor bx,bx ; BX = logical cluster number = 0 ;AN000; + mov ax,es:[di].FH_Phys_Clus_Num ;AN000; + push ax ; first phys clus of current hdr ;AN000; + push bx ; first logic clus (0) of cur hdr ;AN000; + mov fully_flag,0 ; partially found case ;AN000; + jmp short Look_Make_MRU_Hdr ; make current header MRU header ;AN000; + + +;-------------------------------------------------------------------------- +; Get last physical and logical cluster number of the previous extent +;-------------------------------------------------------------------------- +Look_Get_Prev_Extent: + mov di,Prev_Extn_Ptr ; DI-->Previous extent ;AN000; + mov ax,es:[si].EH_Logic_Clus_Num ; AX = First logical cluster number ;AN000; + dec ax ; of current extent ;AN000; + mov bx,es:[di].EH_Logic_Clus_Num ; continuity to last logical clus num ;AN000; + add bx,es:[di].EH_Count ; of previous extent ?? ;AN000; + cmp ax,bx ;AN000; + jne Look_first_partial2 ; no, partially found ;AN000; + +; Fully found case + mov bx,es:[si].EH_Phys_Clus_Num ; BX = First physical cluster number ;AN000; + mov ax,es:[di].EH_Phys_Clus_Num ; AX = Last physical cluster number ;AN000; + add ax,es:[di].EH_Count ; from previous extent ;AN000; + push bx ; BX = 1st phys clus num from cur extn ;AN000; + push ax ; AX = last phys clus num from prev extn ;AN000; + mov fully_flag,1 ; FULLY found case ;AN000; + jmp short Look_Make_MRU_Hdr ; mov current header to top of OPEN que ;AN000; + + +Look_First_Partial2: + mov bx,es:[di].EH_Logic_Clus_Num ; BX = First Logical cluster number ;AN000; + ; of current extent + add bx,es:[di].EH_Count ; BX = Last Logic clus from prev extn ;AN000; + mov ax,es:[di].EH_Phys_Clus_Num ; AX = First physical cluster number ;AN000; + ; of previous extent + add ax,es:[di].EH_Count ; last phys clus num of prev extent ;AN000; + push ax ; AX = last phys clus of prev extent ;AN000; + push bx ; BX = last logic clus of prev extent ;AN000; + mov fully_flag,0 ; partially found case ;AN000; + jmp short Look_Make_MRU_Hdr ; make current header MRU header ;AN000; + + + +;---------------------------------------------------------------------------- +; If the given cluster number matches with any logic cluster number starting +; from 2nd and above, then fully found. Return BX=Phys clus num[log_clusnum] +; and DI=Phys clus num[log_clusnum-1] +;---------------------------------------------------------------------------- +Look_Extn_Within: + mov si,Cur_Extn_Ptr ; SI-->Current extent ;AN000; + sub cx,es:[si].EH_Logic_Clus_Num ;AN000; + mov di,es:[si].EH_Phys_Clus_Num ; DI = first phys clus num of ;AN000; + ; current extent + add di,cx ; DI = Phys clus num [logic clus num] ;AN000; + mov bx,di ; ;AN000; + dec bx ; BX = Phys clus num [logic clus num -1] ;AN000; + push di ; DI = Phys clus num [logic clus num] ;AN000; + push bx ;AN000; + mov fully_flag,1 ; fully found case ;AN000; + jmp short Look_Make_MRU_Hdr ; make current header to top of OPEN Que ;AN000; + + +;-------------------------------------------------------------------------- +; Given extent is above the upper limit of the current extent, but lower than the +; next extent. In this case, cluters are partially found. Return BX = last +; logical cluster number of the previous extent and DI = last physical cluster +; number of the previous extent. +;---------------------------------------------------------------------------- +Look_Proc_Prev: + mov si,Prev_Extn_Ptr ; SI-->Previous extent ;AN000; + mov bx,es:[si].EH_Logic_Clus_Num ; DI = first logic clus num of prev ;AN000; + ; extent + mov di,es:[si].EH_Phys_Clus_Num ; BX = first phys clus num of prev ;AN000; + ; extent + add di,es:[si].EH_Count ; DI = last phys clus number in extent ;AN000; + add bx,es:[si].EH_Count ; BX = last logic clus number in extent + push di ; save clusters to return ;AN000; + push bx ;AN000; + mov fully_flag,0 ; partially found case ;AN000; + +;---------------------------------------------------------------------------- +; Move the current header to the top of the OPEN queue +;---------------------------------------------------------------------------- +Look_Make_MRU_Hdr: + cmp Prev_Hdr_Ptr,-1 ; first header in the Queue ?? ;AN000; + je Look_Dont_Move_To_Top ; yes, dont move to top ;AN000; + + CALL MAKE_MRU_HEADER ;AN000; + +Look_Dont_Move_To_Top: + cmp fully_flag, 0 ; fully found ?? ;AN000; + je Look_set_carry ; no, partially found ;AN000; + clc ; fully found ;AN000; + jmp short Look_Restore ; restore registers ;AN000; + +Look_Set_Carry: + stc ; set flag for partially found ;AN000; + +Look_restore: + pop bx ; restore values to be reurned + pop di ; to DOS + +Look_Exit: + nop + CALL Check_it + ret ; exit + +FK_LOOKUP endp + + + + + + + +;---------------------------------------------------------------- +; PROCEDURE: Fk_Truncate +; +; FUNCTION: Using the given physical and logical clutser numbers, +; find the extent which contains the given cluster number. +; Delete all clusters folloing the given cluster and the +; subsequent extents and free the buffers. +; +; INPUT: CX = First Physical Cluster Number of the file +; BX = Logical Cluster Number +; DL = Drive number +; +; OUTPUT: CY = 0 Extents are truncated +; +; CY = 1 Extent no found DI = 0 +; +; ROUTINES REFERENCED: Find_File_Header, Find_Extent +; +; REVISION HISTORY: New (5/87) +; +; COPYRIGHT: "MS DOS 4.00 Fastopen Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licensed Material - Property of Microsoft " +; +;--------------------------------------------------------------- + +Fk_TRUNCATE PROC FAR + + push cs ; establish addressability ;AN000; + pop ds ; DS --> code segment ;AN000; + assume ds:Cseg_Seek ;AN000; + mov es, Seek_Name_Cache_Seg ; setup cache buff segment register ;AN000; + assume es:Cseg_Init ; ES --> cache buffer segment ;AN000; + mov First_Phys_Clusnum,cx ; save phys cluster number ;AN000; + mov Logical_ClusNum,bx ;AN000; + mov func_cod,al + +;-------------------------------------------------------------------------- +; Search for Drive Cache buffer using Drive ID in DL +;-------------------------------------------------------------------------- + CALL FIND_DRIVE_HEADER ; get drive buffer ;AN000; + jnc Trunc_search_hdr ; if found, search for file header ;AN000; + jmp Trunc_Exit ; if not found, error ;AN000; + ;AN000; +;-------------------------------------------------------------------------- +; Search for a header in the OPEN Queue using given physical clusternum +;-------------------------------------------------------------------------- +Trunc_Search_Hdr: + inc es:[di].Extent_Count ; ;***; + mov si,es:[di].MRU_Hdr_Ptr ; SI-->first header in the ;AN000; + ; in the OPEN Queue + mov cx,First_Phys_Clusnum ; CX = Physical Cluster number ;AN000; + + CALL FIND_FILE_HEADER ; find file header in OPEN Queue ;AN000; + jnc Trunc_Find_extent ; if found, get extent ;AN000; + +;-------------------------------------------------------------------------- +; If the header is not found, create a new header and make it as MRU header +; insert first physical cluster number in the header +;-------------------------------------------------------------------------- + CALL MAKE_NEW_HEADER ; make new header ;AN000; + clc ;AN000; + jmp Trunc_exit ; exit ;AN000; + + +;-------------------------------------------------------------------------- +; Header is found. Next search for the extent which contains the +; given logical cluster number. +;-------------------------------------------------------------------------- +Trunc_Find_Extent: ; ;AN000; + mov Cur_Hdr_Ptr,di ; save current pointer ;AN000; + mov si,es:[di].FH_Next_Extn_Ptr ; SI-->first extent in the ;AN000; + ; current header + cmp si, -1 ; any extent under this header ?? ;AN000; + je trunc_no_extent ; none, exit ;AN000; + mov cx,Logical_Clusnum ; CX = given logical cluster number ;AN000; + + CALL FIND_EXTENT ; find the extent ;AN000; + jnc Trunc_shrink_extent ; found extent ?? ;AN000; + +Trunc_No_Extent: ; extent not found + xor di,di ; no, return DI = 0 ;AN000; + clc ; clear carry + jmp Trunc_exit ; exit ;AN000; + + + +;-------------------------------------------------------------------------- +; Found extent. Shrink the current extent and delete all subsequent extents. +; If the given logic clus num is the first cluster number in current extent, +; then delete the current extent and the subsequent ones. +; DI--->Extent found (starting extent) +;-------------------------------------------------------------------------- +Trunc_Shrink_Extent: + mov bx,Logical_Clusnum ;AN000; + cmp bx,es:[di].EH_Logic_Clus_Num ; first logic cluster match ?? ;AN000; + jne shrink_cur_extent ; no, shrink current extent ;AN000; + +;-------------------------------------------------------------------------- +; First logical clus num matched. mark previous header or extent as last +; DI--->Extent found (starting extent) +;-------------------------------------------------------------------------- + mov si,es:[di].EH_Prev_Extn_Ptr ; SI-->Previous extent ;AN000; + cmp si, -1 ; any previous extent ?? ;AN000; + je trunc_no_prev ; no, jump ;AN000; + mov es:[si].EH_Next_Extn_Ptr,-1 ; mark previous extent as last extn ;AN000; + mov si,di ; save the current extent ptr ;AN000; + mov cx, 0 ; CX = buffer release counter ;AN000; + jmp trunc_more ; release successive extents ;AN000; + +;-------------------------------------------------------------------------- +; Previous one is header. Mark so that there is no extents under it +;-------------------------------------------------------------------------- +Trunc_No_Prev: + mov si,Cur_Hdr_Ptr ; get current header ;AN000; + mov es:[si].FH_Next_Extn_Ptr,-1 ; mark header for no extent ;AN000; + mov es:[si].FH_MRU_Extn_Ptr, -1 + mov si,di ; save the current extent ptr ;AN000; + mov cx, 0 ; CX = buffer release counter ;AN000;;AN000; + jmp short trunc_more ; release the extent ;AN000; + + +Shrink_Cur_Extent: + sub bx,es:[di].EH_Logic_Clus_Num ; compute the amount to shrunk ;AN000; + dec bx ;AN000; + mov es:[di].EH_Count,bx ; save it in count to shrink extent ;AN000; + +;-------------------------------------------------------------------------- +; Mark the current extent as the last extent and delete subsequent extents. +;-------------------------------------------------------------------------- + mov si,es:[di].EH_Next_Extn_Ptr ; SI-->Next extent ;AN000; + cmp si,-1 ; current extent last extent ?? ;AN000; + jne Trunc_Last_extent + jmp Trunc_Make_MRU_Hdr ; YES, In this case no subsequent ;AN000; + ; extents left to delete. +Trunc_Last_Extent: + mov es:[di].EH_Next_Extn_Ptr, -1 ; NO, mark last extent ;AN000; + xor cx,cx ;AN000; + +;-------------------------------------------------------------------------- +; Remove extents and release the buffer +; SI--->Current extent +;-------------------------------------------------------------------------- +Trunc_More: + push si ; save the beginning of first ;AN000; + ; extent to be deleted +TRUNC_LOOP: ; loop for subsequent extents + mov ax, -2 ; mark current extent as free ;AN000; + mov es:[si],ax ; discontinuous free areas ;AN000; + add cx, SIZE Extent_Header ; add size of extent ;AN000; + + mov ax,es:[si].EH_Next_LRU_Ptr ; AX = address of Next LRU extent + cmp ax, -1 ; any next LRU extent?? + jne Trunc_Set_Next_LRU ; yes - there is a next LRU extent + +;----------------------------------------------------------------------------- +; No - this is the LRU extent +;----------------------------------------------------------------------------- + mov di,es:[si].EH_Prev_LRU_Ptr ; no - DI=address of previous LRU extent + cmp di, -1 ; any prev LRU extent ?? + je Trunc_Mark_Prev_Hdr ; no - previous is header + mov es:[di].EH_Next_LRU_Ptr, -1 ; yes - mark previous extnt LRU extent + jmp short Trunc_Chk_Next_ext ; no - check next adj extent + +Trunc_Mark_Prev_Hdr: + mov di, Cur_Hdr_Ptr ; DI = address of current header + mov es:[di].FH_Next_Extn_Ptr,-1 ; mark header for no extent ;AN000; + mov es:[di].FH_MRU_Extn_Ptr, -1 + jmp short Trunc_Chk_Next_Ext ; look for next extent + +;----------------------------------------------------------------------------- +; There is a next LRU extent AX-->Next_LRU_Extent +;----------------------------------------------------------------------------- +Trunc_Set_Next_LRU: + mov di,es:[si].EH_Prev_LRU_Ptr ; DI = address of previous LRU extent + cmp di, -1 ; any previous LRU extent ?? + jne Trunc_Set_Prev_LRU ; yes - connect prev LRU to Next LRU + + mov di, Cur_Hdr_Ptr ; DI = address of current header + mov es:[di].FH_MRU_Extn_Ptr, ax ; Connect next LRU extent to Hdr + push si ; save current extent + mov si,ax + mov es:[si].EH_Prev_LRU_Ptr, -1 ; mark no previous extent + pop si ; resetore current extent + jmp short Trunc_Chk_Next_Ext + + +Trunc_Set_Prev_LRU: ; DI-->Previous LRU extent + mov es:[di].EH_Next_LRU_Ptr,ax ; connect previous LRU to Next LRU extent + push si ; save Current extent + mov si,ax ; SI-->Next LRU extent + mov es:[si].EH_Prev_LRU_Ptr, di ; set previous LRU header address + pop si ; get current extent + + +Trunc_Chk_Next_Ext: ; SI-->Current extent + mov ax,es:[si].EH_Next_Extn_Ptr ; AX-->next extent ;AN000; + cmp ax, -1 ; last extent ? ;AN000; + je Trunc_Update_Free_Size ; yes, jump ;AN000; + + mov es:[si].FH_Next_Hdr_Ptr,ax ; connect freed buffers togther ;AN000; + mov si,ax ; SI-->next extent ;AN000; + jmp Trunc_Loop ; delete next extent ;AN000; + +;------------------------------------------------------------------------- +; Update free size in the File header and connect the FREE_Ptr to the first +; extent released and connect the old Free_Ptr to end of the last extent +; SI--->Current extent +;------------------------------------------------------------------------- +Trunc_Update_Free_Size: ; SI-->Last extent released + mov di,Drive_Hdr_Ptr ; DI-->Drive header ;AN000; + add es:[di].Free_Size,cx ; update free area in drive header ;AN000; + +Trunc_Join_Free_Area: +; At this point SI-->Last extent + mov ax,es:[di].Free_Ptr ;AN000; + mov es:[si].EH_Next_Extn_Ptr,ax ; connect last extent under this ;AN000; + ; header to the Free area ;AN000; + pop ax ; beginning of truncated extent ;AN000; + mov es:[di].Free_Ptr,ax ; connect current extent to ;AN000; + ; the beginning of truncated extent + +;-------------------------------------------------------------------------- +; Make the Current header MRU header ( move current header to top of current Q) +;-------------------------------------------------------------------------- +Trunc_make_MRU_Hdr: + cmp Prev_Hdr_Ptr,-1 ; first header in the Queue?? ;AN000; + jne Trunc_move_Hdr + clc + jmp short Trunc_Exit ; yes, dont move to top ;AN000; + +Trunc_move_Hdr: + CALL MAKE_MRU_HEADER ; move header to TOP of the Queue ;AN000; + clc + +Trunc_Exit: + CALL Check_it + ret ; return ;AN000; + +FK_TRUNCATE ENDP + + + + + + + + +;----------------------------------------------------------------------------- +; Procedure: PURGE_BUFFERS +; +; Function: Reset both extent and name cache buffers of a specific +; drive id +; +; Input: DL = drive ID +; +; Output: Buffers are initialized +; +; REVISION HISTORY: New (5/87) +; +; COPYRIGHT: "MS DOS 4.00 Fastopen Utility" +; "Version 4.00 (C) Copyright 1988 Microsoft" +; "Licensed Material - Property of Microsoft " +; +;----------------------------------------------------------------------------- + +FK_PURGE PROC FAR ; Purge Cache buffers + + push cs + pop ds ; DS=Code seg id used for addressing + ASSUME ds:Cseg_Seek ; local variables ;AN000; + + mov si,Seek_Extent_Drive_Buff ; SI-->beginning of extent drive ;AN000; + mov es,Seek_Name_Cache_Seg ; ES = addressability to Cseg_Init ;AN000; + ASSUME es:Cseg_Init ; ;AN000; + mov cx,Seek_Num_Of_drives ; number of drives + +Main_Loop2: ; ES:SI-->cache buffer + mov ax,es:[si].Drive_Number ; get drive id + cmp al,dl ; drive id found ?? + je purge_buffer ; yes - purge drive id buffer + mov ax, size Drive_Header ; ax size of drive heder + add ax, es:[si].Buff_Size ; ax = offset to next header + add si,ax ; (2/11)SI-->next drive header ;AN000; + LOOP main_loop2 ; try next header + +Purge_Buffer: ; SI-->drive header + mov es:[si].MRU_Hdr_Ptr,-1 ; Make OPEN QUEUE empty ;AN000; + mov es:[si].CLOSE_Ptr,-1 ; Make CLOSE QUEUE empty ;AN000; + mov cx,es:[si].BUFF_size ; drive extent cache size ;AN000; + mov es:[si].FREE_Size,cx ; set drive free buffer size ;AN000; + mov ax,si + add ax, size Drive_Header ; ax = size of drive header + mov es:[si].FREE_Ptr,ax ; set Free buffer address + +; Makesure to fill extent cache buffer with zeros. Otherwise, Free Mark left +; previous run will generate illegal Free_Buff pointer. + mov al,0 + add si, size Drive_Header ; SI-->first extent area +Ext_loop: ; fill extent cahe buffer with zeros + mov es:[si],al ; CX = extent cache size + inc si ; next byte + Loop Ext_Loop ; make it zero + +FK_Exit: + clc + CALL Check_it + ret ;AN000; + +FK_PURGE ENDP + + + + + + + +;---------------------------------------------------------------------- +; ******* SUPPORT ROUTINES ******* +;---------------------------------------------------------------------- +; +;---------------------------------------------------------------------- +; PROCEDURE: Find_Drive_Header +; +; FUNCTION: Find starting address of drive header in extent Cache Buffer using +; drive ID in DL +; +; INPUT: DL = drive id +; Extent_Drive_Buff (Ptr to the beginning of extent buffer) +; ES--> Cache Buffer Segment +; +; OUTPUT: If Carry = 0 DI --> Drive header +; Drive_Hdr_Ptr = address of drive header +; +; If Carry = 1 Drive buffer not found +; +; NOTE: If drive id in DL is same as the drive id in previous request, +; no need to search the drive header. Use the previous drive header +; +;---------------------------------------------------------------------- + +FIND_DRIVE_HEADER PROC NEAR + + mov di,Drive_Hdr_Ptr ; DI-->address of prev drive header + cmp drv_id,dl ; drive id same as previous drive id (1/11/88) + jne Search_drv_hdr ; no - search drive header + clc ; yes - dont search + jmp short drive_exit ; exit + +Search_Drv_Hdr: + mov cx,Seek_Num_of_Drives ; get number of drives ;AN000; + mov si,Seek_Extent_Drive_Buff ; SI-->start of extend drive hdr ;AN000; + +Drive_Loop: + mov al,es:[si] ; get drive ID from cache drive hdr ;AN000; + cmp al,dl ; found ?? ;AN000; + je drive_buff_found ; yes, exit ;AN000; + cmp es:[si].Next_Drv_Hdr_Ptr,-1 ; last header ?? ;AN000; + je drive_Buff_not_found ; yes - drive header not found ;AN000; + mov si,es:[si].Next_Drv_Hdr_Ptr ; SI-->next drive header ;AN000; + dec cx ; update drive count ;AN000; + jz drive_Buff_not_found ; last drive ;AN000; + jmp drive_Loop ; search for more ;AN000; + +Drive_Buff_Not_Found: ; drive buffer not found + stc ; set carry flag ;AN000; + jmp short Drive_Exit ; exit ;AN000; + +Drive_Buff_Found: ; drive buffer found + mov drv_id,dl ; save drive id + mov Drive_Hdr_ptr,si ; save drive buffer pointer ;AN000; + mov di,si ; DI-->drive header ;AN000; + clc ;AN000; + +Drive_Exit: ; return + ret ;AN000; + +FIND_DRIVE_HEADER endp + + + + + +;--------------------------------------------------------------- +; PROCEDURE: Find_File_Header +; +; FUNCTION: Find starting address of the specific file header with +; a specific starting physical cluster number. Also +; determine the type of header found. +; +; INPUT: SI --> First header in the queue +; CX = First Physical Cluster Number (file id) +; ES--> Cache Buffer Segment id +; +; OUTPUT: If Carry = 0 DI --> header found +; Cur_Hdr_Ptr = address of header found +; Prev_Hdr_Ptr = address of previous header +; +; Prev_Hdr_Ptr = -1 No Previous Header +; +; hdr_flag - Type of header found +; = 0 Header between first & last in queue +; = 1 Single header in the queue +; = 2 First header in the queue +; = 3 LRU (Last) header in the queue +; +; If Carry = 1 Header not found +; +;--------------------------------------------------------------- + +FIND_FILE_HEADER PROC NEAR + + push si ; save registers ;AN000; + push cx ;AN000; + + cmp si, -1 ; any file header in this queue ?? ;AN000; + jne Fh_search_hdr ; yes, search for it ;AN000; + stc ; no, set carry and return ;AN000; + jmp short Fh_Exit ;AN000; + +Fh_Search_Hdr: + mov Prev_Hdr_Ptr,-1 ; reset flags ;AN000; + mov Hdr_Flag, 0 ; reset header type flag ;AN000; + +Fh_Loop1: + cmp es:[si].FH_Phys_Clus_Num,CX ; check current header ;AN000; + jne Fh_next_header ; if not found branch ;AN000; + mov di,si ; DI --> header found ;AN000; + mov Cur_Hdr_Ptr,si ; save current Hdr pointer ;AN000; + jmp short Fh_header_found ; then take exit ;AN000; + +Fh_Next_header: ; else try next header + mov ax,es:[si].FH_Next_Hdr_ptr ; get address of next header ;AN000; + cmp ax,-1 ; is this last header?? ;AN000; + je Fh_not_found ; yes, header no found ;AN000; + + mov Prev_Hdr_Ptr,si ; save previous header ;AN000; + mov si,ax ; SI= next header ;AN000; + jmp Fh_Loop1 ; check next header ;AN000; + +; Determine the type of header found +Fh_Header_Found: ; header found + cmp Prev_Hdr_Ptr, -1 ; any previous headers ?? ;AN000;;AN000; + jne Fh_LRU ; yes, jump ;AN000; + cmp es:[si].Fh_Next_Hdr_Ptr, -1 ; any headers following this hdr ?? ;AN000; + jne Fh_First ; yes, jump ;AN000; + mov Hdr_Flag, 1 ; single header in the queue ;AN000; + clc ; ;AN000; + jmp short FH_Exit ; exit ;AN000; + +Fh_First: + mov Hdr_Flag, 2 ; Header found is first header in QUE ;AN000; + clc ; set flag ;AN000; + jmp short FH_Exit ; exit ;AN000; + +Fh_LRU: + cmp es:[si].Fh_Next_Hdr_Ptr, -1 ; Last header in the queue ?? ;AN000; + jne Fh_middle_hdr ; no, Header between first and last ;AN000; + mov Hdr_Flag, 3 ; set flag indicating LRU header ;AN000; + clc ;AN000; + jmp short Fh_Exit ; exit ;AN000; + ;AN000; +Fh_Middle_Hdr: + clc ;AN000; + jmp short Fh_Exit ; exit ;AN000; + +Fh_Not_found: + stc ; header not found ;AN000; + +Fh_Exit: + pop cx ;AN000; + pop si ;AN000; + ret ; return ;AN000; + +FIND_FILE_HEADER ENDP + + + + + + + +;--------------------------------------------------------------- +; PROCEDURE: Find_Extent +; +; FUNCTION: Find starting address of the specific Extent that contains +; the given logical cluster mumber. +; Verifiy that the extent found is the LRU Extent. +; +; INPUT: SI --> First Extent under current queue +; CX = Logical Cluster number to be searched +; ES--> Cache Buffer Segment Id +; +; OUTPUT: If Carry = 0 DI --> Extent found +; Cur_Extn_Ptr = address of extent found +; Prev_Extn_Ptr = address of previous extent +; IF Extn_Flag = 1, extent found is the only +; extent under this header +; +; If Carry = 1 Extent not found +; +; REVISION HISTORY: New (5/87) +;--------------------------------------------------------------- + +FIND_EXTENT PROC NEAR + + push si ; save registers ;AN000; + push cx ;AN000; + ;AN000; + mov Prev_Extn_Ptr,-1 ; reset flags + mov Extn_Flag, 0 ;AN000; + ;AN000; +Eh_Loop1: + cmp cx,es:[si].EH_Logic_Clus_Num ;AN000; + jl Eh_Next_Extn ; try next extent ;AN000; + mov ax,es:[si].EH_Count ; get range ;AN000; + add ax,es:[si].EH_Logic_Clus_Num ; get upper range ;AN000; + cmp cx,ax ;AN000; + jg Eh_Next_Extn ; try next extent ;AN000; + +Eh_Not_LRU: + mov di,si ; DI --> Extent found ;AN000; + mov Cur_Extn_Ptr,si ; save current extent pointer ;AN000; + clc ; set flag ;AN000; + jmp Eh_Extn_found ; then take exit ;AN000; + +Eh_Next_Extn: ; else try next extent + mov ax,es:[si].EH_Next_Extn_ptr ; get address of next extent ;AN000; + cmp ax,-1 ; is this last extent?? ;AN000; + je Eh_Not_Found ; yes, exit ;AN000; + mov Prev_Extn_Ptr,si ; save previous extent ;AN000; + mov si,ax ; SI=next extent ;AN000; + jmp Eh_Loop1 ; check next extent ;AN000; + + stc ; else set flag for extent not found ;AN000; + jmp short Eh_Exit ; then exit ;AN000; + +Eh_Extn_Found: ; Extent found + cmp Prev_Extn_Ptr, -1 ; any previous extents ?? ;AN000; + jne Eh_yes ; yes, jump ;AN000; + cmp es:[di].Eh_Next_Extn_Ptr, -1 ; any extents following this extents ?? ;AN000; + jne Eh_yes ; yes, jump ;AN000; + mov Extn_Flag, 1 ; no, set flag indicating single extnt ;AN000; + ; in the queue +Eh_Yes: + clc ;AN000; + jmp short Eh_Exit ; exit ;AN000; + +Eh_Not_Found: ; extent not found + stc ;AN000; + +Eh_Exit: + pop cx ;AN000; + pop si ;AN000; + + ret ; return ;AN000; + +FIND_EXTENT ENDP + + + + + + +;--------------------------------------------------------------------------- +; PROCEDURE: FIND_CLUSTER_LOCATION +; +; FUNCTION: Find starting address of a specific extent which identifies +; the relative position of the new cluster in the queue. +; +; INPUT: SI--> First extent under current header +; ES--> Cache Buffer Segment +; +; OUTPUT: If Carry = 0 Cluster location identified +; Cur_Extn_Ptr = Current extent +; Prev_Extn_Ptr = Previous extent +; +; Find_Flag = 1 Clusters are contiguous in +; the LO end of the current extent +; +; Find_Flag = 2 Clusters are contiguous in +; the HI end of the current extent +; +; Find_Flag = 3 Clusters belong to a new +; extent between current and previous +; extent +; +; Find_Flag = 4 Clusters belong to a new +; extent at the end of the queue +; Cur_Extn_Ptr-->Last extent in queue +; +; Find_Flag = 5 Clusters belong to a new +; extent between current and next +; +; If Carry = 1 Clusters already exist +; +;----------------------------------------------------------------------- + + +FIND_CLUSTER_LOCATION PROC NEAR + +;-------------------------------------------------------------------------- +; Check to see that the given logical cluster number falls within the +; current extent. If true it is an error. +;-------------------------------------------------------------------------- + push di + mov Prev_Extn_Ptr, -1 ; initialize the flag ;AN000; + mov Cur_Extn_Ptr,si ; SI-->First extent under header ;AN000; + mov Find_Flag, -1 ; reset with illegal value + ;AN000; +Fe_LOOP1: + mov ax,es:[si].EH_Logic_Clus_Num ; AX = starting logi clus number ;AN000; + mov bx,Logical_Clusnum ; BX = given logical clus num ;AN000; + cmp bx,ax ; LOW end ?? ;AN000; + jl Fe_Chk_Low_end ; yes - jump ;AN000; + add ax,es:[si].EH_Count ; ending logical clus number ;AN000; + cmp bx,ax ; HIGH end ?? ;AN000; + jg Fe_Chk_High_end ; yes - jump ;AN000; + +;-------------------------------------------------------------------------- +; Found the given logical cluster number within the extent. +; This is a normal condition. In this case the clusters wont be insterted. +;-------------------------------------------------------------------------- + stc ; set flag + jmp Fe_Extent_Exit ; return ;AN000; + + +;-------------------------------------------------------------------------- +; If not in the extent, then see the logical clus number has continuity at +; LOW end of the current extent. +;-------------------------------------------------------------------------- +Fe_Chk_LOW_END: + mov ax,es:[si].EH_Logic_Clus_Num ; starting logi clus number ;AN000; + dec ax ; one below the lowest ;AN000; + mov bx,Logical_Clusnum ; BX = given logical clus num ;AN000; + cmp bx,ax ; contiguous at LOW end ?? ;AN000; + jl Fe_Curr_Prev ; no, build a new extent between ;AN000; + ; current and previous +; Logical clus has continuity at low end. Now check physical cluster number +; foe continuity. + mov ax,es:[si].EH_Phys_Clus_Num ; starting Phys clus number ;AN000; + dec ax ; one below the lowest in the extent ;AN000; + mov bx,Physical_Clusnum ; BX = given logical clus num ;AN000; + cmp bx,ax ; within low end ?? ;AN000; + jne Fe_Curr_Prev ; no, create a new extent between ;AN000; + ; current and previous extent + mov Find_Flag,1 ; yes, set flag for LOW END continuity ;AN000; + jmp Fe_Extent_found ; then RETURN ;AN000; + + +;-------------------------------------------------------------------------- +; Check the logical clus number has continuity at High end of the current +; extent cluster range. Check physical cluster number has continuity at the +; high end. If true, check the first logical and phys cluster number is the +; the same as this one. In this case clusters exist and therefore wont be +; insterted. +;-------------------------------------------------------------------------- +Fe_CHK_HIGH_END: + mov ax,es:[si].EH_Logic_Clus_Num ; starting logi clus number ;AN000; + add ax,es:[si].EH_Count ; ending logical clus number ;AN000; + inc ax ;AN000; + mov bx,Logical_Clusnum ; BX = given logical clus num ;AN000; + cmp bx,ax ; within high end ?? ;AN000; + jg Fe_Chk_Next_Extent ; no, check next extent ;AN000; + +; Logical clus num has high end continuity, Check the Physical cluster number +; for continuity. + mov ax,es:[si].EH_Phys_Clus_Num ; starting phys clus number ;AN000; + add ax,es:[si].EH_Count ; ending phys clus number ;AN000; + inc ax ;AN000; + mov bx,Physical_Clusnum ; BX = given logical clus num ;AN000; + cmp bx,ax ; within high end ?? ;AN000; + jne Fe_Chk_Next_Extent ; no - check next extent ;AN000; + ; +; Yes - check first logical and physical cluster number of next extent + mov di,es:[si].EH_Next_Extn_Ptr ; get address of next extent ;AN000; + cmp di, -1 ; any next extent ?? + je Fe_High_End ; none - jump + mov ax,es:[di].EH_Logic_Clus_Num ; starting logi clus number ;AN000; + cmp ax,Logical_Clusnum ; logical cluster matches ?? + jne Fe_high_end ; no - jump + mov ax,es:[di].EH_Phys_Clus_Num ; starting phys clus number ;AN000; + cmp ax,Physical_Clusnum ; physical cluster match ?? + jne Fe_High_End ; no -jump + stc ; clusters already exist in next extent + jmp short Fe_Extent_Exit ; return ;AN000; + +Fe_High_End: + mov Find_Flag,2 ; set flag for HIGH end continuity ;AN000; + jmp short Fe_Extent_found ; then RETURN ;AN000; + + +Fe_Chk_Cur_Next: + cmp es:[si].EH_Next_Extn_Ptr, -1 ; Current extent last extent ?? ;AN000; + je Fe_flag_4 ; yes, set flag-4 ;AN000; + + mov Find_Flag,5 ; set flag for new extent between ;AN000; + jmp short Fe_Extent_Found ; current and next extent ;AN000; + +Fe_Flag_4: + mov Find_Flag,4 ; set flag for new extent at the ;AN000; + jmp short Fe_Extent_Found ; bottom end of current queue ;AN000; + +;-------------------------------------------------------------------------- +; Given cluster number has no continuity but must stay between current extent +; and previous extent +;-------------------------------------------------------------------------- +Fe_CURR_PREV: + mov Find_Flag,3 ; set flag for between current and prev ;AN000; + jmp short Fe_Extent_found ; then RETURN ;AN000; + + +;-------------------------------------------------------------------------- +; Given cluster number has no continuity. Try the next extent. +;-------------------------------------------------------------------------- +Fe_Chk_NEXT_EXTENT: ; else try next extent + mov ax,es:[si].EH_Next_Extn_Ptr ; get address of next extent ;AN000; + cmp ax,-1 ; is this last extent ?? ;AN000; + je Extent_at_Bottom ; yes, Clustr belongs to a new ;AN000; + ; extent at the bottom ;AN000; + mov Prev_Extn_Ptr,si ; save current extend as previous extnt + mov si,ax ; SI-->Next extent ;AN000; + mov Cur_Extn_Ptr, si ; save new extent as cur extent ;AN000; + jmp Fe_Loop1 ; check next extent ;AN000; + + +;-------------------------------------------------------------------------- +; Given cluster number has no continuity but stays in a new extent at +; bottom (last) of the current queue. +;-------------------------------------------------------------------------- +Extent_AT_BOTTOM: + mov Find_Flag,4 ; else set flag for new extent ;AN000; + +Fe_Extent_Found: + clc ;AN000; + +Fe_Extent_Exit: + pop di + + RET ; exit ;AN000; + + +FIND_CLUSTER_LOCATION ENDP + + + + + + + +;----------------------------------------------------------------------- +; PROCEDURE: FIND_LRU_HEADER +; +; FUNCTION: Find address of the LRU header in the current queue +; +; INPUT: SI --> First header in the current queue +; ES--> Cache Buffer Segment +; +; OUTPUT: DI --> LRU header found +; +; LRU_Prev_Hdr = Previous header address +; LRU_Hdr = Address of LRU header found +; If Hdr_Flag = 1 - Header found is only header in the queue +; +;----------------------------------------------------------------------- + +FIND_LRU_HEADER PROC NEAR + + push bx ;AN000; + mov hdr_flag,0 ; initilialize flags ;AN000; + mov LRU_Prev_Hdr, -1 ; ;AN000; + +Flh_Loop1: + cmp es:[si].FH_Next_Hdr_Ptr,-1 ; current header is last hdr ? ;AN000; + jne Flh_next_header ; if not check next header ;AN000; + mov di,si ; DI --> LRU header found ;AN000; + mov LRU_Hdr,si ; save it ;AN000; + jmp short Flh_header_found ; then take exit ;AN000; + +Flh_Next_Header: ; else try next header + mov LRU_Prev_Hdr,si ; save previous header address ;AN000; + mov si,es:[si].FH_Next_Hdr_ptr ;AN000; + jmp Flh_Loop1 ; check next header ;AN000; + +Flh_Header_Found: + cmp LRU_Prev_Hdr, -1 ; any previous header ?? ;AN000; + je F1h_Set_Flag ; no, set flag ;AN000; + clc ; yes ;AN000; + jmp short F1H_Exit ; exit ;AN000; + +F1h_Set_Flag: + mov hdr_flag,1 ; LRU header is the only hdr in queue ;AN000; + clc ;AN000; + +F1h_Exit: ; exit + pop bx ;AN000; + + ret ;AN000; + +FIND_LRU_HEADER endp + + + + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; PROCEDURE: FIND_LRU_EXTENT +; +; FUNCTION: Find address of LRU Extent under current header +; +; INPUT: ES--> Cache Buffer Segment +; SI--> Header to be searched +; +; OUTPUT: If CY = 0 LRU_Prev_Extent = Previous extent to the LRU extent +; LRU_Extent = LRU extent found +; Extn_Flag = 1 Extent is the only extent under header +; +; If CY = 1 Not found +; +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +FIND_LRU_EXTENT PROC NEAR + + mov LRU_Prev_Extent, -1 ; reset flags ;AN000; + mov LRU_Extent, -1 ; ;AN000; + mov Extn_Flag, 0 + mov si, es:[si].FH_MRU_Extn_Ptr ; SI--> First extent under header + cmp si, -1 ; any extent under this header ?? + jne Fle_Loop1 ; yes - check extent + stc ; no - set flag + jmp Fle_Exit ; exit + +Fle_Loop1: + cmp es:[si].EH_Next_LRU_Ptr,-1 ; last extent in the queue?? + jne Fle_next_extent ; if not found branch ;AN000; + mov LRU_Extent,si ; save LRU extent address + jmp short Fle_Extend_found ; exit + +Fle_Next_Extent: ; else try next extend + mov LRU_Prev_Extent,si ; save previous extent address + mov si,es:[si].EH_Next_LRU_Ptr ; get address of next extent + jmp Fle_Loop1 ; check next extent ;AN000; + +Fle_Extend_Found: + cmp LRU_Prev_Extent, -1 ; any previous extent ?? + je Fle_Set_Flag ; no - set flag + clc ; ;AN000; + jmp short Fle_Exit + +Fle_Set_Flag: + mov Extn_Flag, 1 ; set flag to indicate only flag + clc + +Fle_Exit: + ret ; exit ;AN000; + +FIND_LRU_EXTENT ENDP + + + + + + + +;---------------------------------------------------------------------- +; PROCEDURE: Make_New_Header +; +; FUNCTION: Create a new header in the next available free area. +; Initialize the new header and make it MRU header ( move it +; to the top of the queue). If no free space in OPEN queue, delete +; and extent from the CLOSE queue. If no space in CLOSE queue, then +; delete an extent from OPEN Queue to make space. +; +; INPUT: Drive_Hdr_Ptr - Address of drive header +; Free_Ptr - Address of FREE area +; ES--> Cache Buffer Segment +; +; OUTPUT: Header is created +; +;---------------------------------------------------------------------- + +MAKE_NEW_HEADER PROC + +; Check if the OPEN Queue was previously empty using two cases. If open queue +; is empty, then the new header should be marked as first header in the queue. + mov Open_Queue_Flag, 0 ; clear flag open queue empty ;AN000; + mov di,Drive_Hdr_Ptr ;AN000; + +; case - 1 + mov ax,es:[di].Free_Size ; FREE size ;AN000; + cmp es:[di].Buff_Size,ax ; both are equal ? ;AN000; + je Make_Set_Entries ; if true, this is the first header ;AN000; + +; case - 2 + cmp es:[di].MRU_Hdr_Ptr, -1 ; check for empty mark ;AN000; + je Make_Set_Entries ; yes, set flag queue empty ;AN000; + jmp short Make_Set_Entry2 ; not empty ;AN000; + +Make_set_Entries: ; set up File Header entries +; When creating first header under drive header, mark header as first +; This flag is set for this purpose. + mov Open_Queue_Flag, 1 ; set flag open queue was empty ;AN000; + +Make_Set_Entry2: + CALL FIND_FREE_BUFFER ; Look for some Free area. If none ;AN000; + ;AN000; + mov di,Drive_Hdr_Ptr ; DI-->Drive header ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov New_Hdr_Ptr,ax ; save new Header address + mov ax,es:[di].Free_Size ;AN000; + + CALL UPDATE_FREE_AREA ; update Free_Ptr and Free_Size ;AN000; + ; create some free area + +;----------------------------------------------------------------------------- +; Connect the new header to the Top of the OPEN Queue. If the Queue is +; previously empty, mark the new header indicating nothing under this header. +;----------------------------------------------------------------------------- +Join_To_Drive_Buff: + mov di, drive_Hdr_Ptr ; DI-->drive buffer ;AN000; + mov si,New_Hdr_Ptr ;AN000; + mov Cur_Hdr_Ptr, si ; save as current header pointer ;AN000; + mov ax,es:[di].MRU_Hdr_Ptr ; connect current header to ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,ax ; previous MRU header + mov es:[di].MRU_Hdr_Ptr,si ; make new header MRU hdr + +; When a header is created, it should contain no extents + mov es:[si].FH_Next_Extn_Ptr,-1 ; mark header with no extents ;AN000; + mov es:[si].FH_MRU_Extn_Ptr,-1 ; ###mark header with no extents ;AN000; + mov es:[si].FH_Refer_Count,1 ; save starting file reference count ;AN000; + mov ax,First_Phys_Clusnum ;AN000; + mov es:[si].FH_Phys_Clus_Num,ax ; save physical cluster number ;AN000; + + cmp Open_Queue_Flag, 1 ; OPEN Queue empty ?? ;AN000; + je Set_Single_Header ; no, jump ;AN000; + clc + ret ;AN000; + +Set_Single_Header: ; yes mark new header as last hdr + mov si,New_Hdr_Ptr ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,-1 ; mark as only header ;AN000; + clc + ret ; exit + +MAKE_NEW_HEADER ENDP + + + + + + +;---------------------------------------------------------------------- +; PROCEDURE: Find_Free_Buffer +; +; FUNCTION: Find free buffer space. If no free space, delete last extent +; under last header in the CLOSE queue. If none in CLOSE queue, +; delete the last extent of the LRU header in the OPEN queue. +; +; INPUT: Drive_Hdr_Ptr - Pointer to drive header +; ES--> Cache Buffer Segment +; +; OUTPUT: Released Header or extent buffer space will be addded to the +; Free area as discontinuous free area. Free size in drive head +; will be updated. +; +; If CARRY = 0 +; Free_Flag: 0 - Free area is continuous +; 1 - Free area is discontinuous +; +; if CARRY = 1 Fatal error ( no free space to spare ) +; +; NOTE: The deleted buffers have size same as the size of a header or extent. +; Each buffers first location contains a marker (-2) to indicate that +; the buffer is a discontinuous buffer. Each buffer is connected to +; the next dicontinous buffer through the 4th word. +; +;---------------------------------------------------------------------- + +FIND_FREE_BUFFER PROC NEAR + + mov di,drive_Hdr_Ptr ; DI-->Drive Header ;AN000; + cmp es:[di].free_size,0 ; any free area left ?? ;AN000; + je Free_Chk_Close_List ; none, check CLOSE queue ;AN000; + + mov si,es:[di].Free_Ptr ; check for discontinuous ;AN000; + mov ax, -2 ;AN000; + cmp es:[si], ax ; discontinuous free buffer?? ;AN000; + je Free_Set_One ; yes, set flag for discontinuous + + mov Free_Flag,0 ; no, clear flag ;AN000; + clc ;AN000; + jmp Free_Exit + +Free_Set_one: + mov Free_Flag,1 ; set flag ;AN000; + clc ;AN000; + jmp Free_exit ; yes, Free space is available ;AN000; + ; exit + + +;-------------------------------------------------------------------------- +; No free space , look for space in CLOSE Queue. Search for the LRU header +; delete the header and any extents under this header. +;-------------------------------------------------------------------------- +Free_Chk_Close_List: + mov si,es:[di].CLOSE_Ptr ; SI-->CLOSE queue ;AN000; + cmp si,-1 ; anything in CLOSE Queue ?? ;AN000; + jne Free_Chk_CLOSE_QUE ; yes - get space from CLOSE queue + jmp short Free_Look_Open_Queue ; if none, make space from OPEN Queue ;AN000; + + +; Else get space from CLOSE queue +Free_Chk_Close_QUE: ; SI-->CLOSE queue + mov si,es:[di].CLOSE_Ptr ; select OPEN Queue ;AN000; + CALL FIND_LRU_HEADER ; find LRU header in CLOSE Queue ;AN000; + ; DI-->LRU header + +; Makesure to save all local variables before calling DELETE +; since, this variables may be altered by DELETE routine. + mov ax,Hdr_Flag + push ax + mov ax,Prev_Hdr_Ptr + push ax + mov ax,Queue_Type + push ax + mov ax,Cur_Hdr_Ptr + push ax + mov ax,First_Phys_Clusnum ; save original first phys from OPEN call + push ax ; in the stack + mov cx,es:[di].FH_Phys_Clus_Num ; CX= starting phys clus num of LRU header + mov From_FreeBuff,1 ; set flag + + push ds + mov ax,Cseg_Main + mov ds,ax + assume ds:Cseg_Main + CALL VECTOR_DELETE ; delete the file + pop ds + assume ds:Cseg_Seek + + mov From_FreeBuff,0 ; clear flag + mov Free_Flag,1 ; set flag to indicate discontinuous free area + pop ax ; restore first phys clus + mov First_Phys_Clusnum,ax ; save it back where it belongs + pop ax ; restore current header + mov Cur_Hdr_Ptr,ax ; save it back where it belongs + pop ax ; restore current header + mov Queue_Type,ax ; save it back where it belongs + pop ax ; restore current header + mov Prev_Hdr_Ptr,ax ; save it back where it belongs + pop ax ; restore current header + mov Hdr_Flag,ax ; save it back where it belongs + clc + jmp Free_exit ; exit ;AN000; + + + +;---------------------------------------------------------------------------- +; No space available in CLOSE Queue . Now get some free space from OPEN Queue +; and add it to the free area. +;---------------------------------------------------------------------------- +Free_Look_Open_Queue: + mov si,es:[di].MRU_Hdr_Ptr ; SI-->First header in OPEN Queue ;AN000; + CALL FIND_LRU_HEADER ; find last header in Queue ;AN000; + ; DI-->last header + mov si,es:[di].FH_MRU_Extn_Ptr ;### SI-->first extent in this header ;AN000; + cmp si, -1 ; any extent under this header ?? ;AN000; + jne Free_Open_Find_Extent ; yes, find last extent ;AN000; + +; if no extents under this header, delete this header and free the space + cmp di,Cur_Hdr_Ptr ; header found is its own header ?? ;AN000; + jne Free_OPen_Mark_Prev ; no - free the header ;AN000; + stc ; Yes - set carry, exit ;AN000; + jmp Free_Exit ; ERROR exit ;AN000; + +Free_Open_Mark_Prev: ; mark previous header as LRU before deleting this header + mov si,LRU_Prev_Hdr ; SI-->previous header ;AN000; + mov es:[si].FH_Next_Hdr_Ptr, -1 ; mark previous header as last hdr ;AN000; + jmp Free_Open_Cl_Buffer ;AN000; + +Free_Open_Find_Extent: + mov si,di ; SI-->header to be searched + CALL FIND_LRU_EXTENT ; ### find last extent in the header ;AN000; + mov di, LRU_Extent ; DI-->LRU extent + cmp Extn_flag,1 ; Is this the only extent in the queue ? ;AN000; + jne free_Open_prev_extn ; no, mark previous extent as last extn ;AN000; + push di ; save pointer to Last extent ;AN000; + mov di,LRU_Hdr ; DI-->LRU header ;AN000; + mov es:[di].FH_Next_Extn_Ptr,-1 ; mark current HEADER with no extents ;AN000; + mov es:[di].FH_MRU_Extn_Ptr,-1 ; ### mark current HEADER with no extents ;AN000; + pop di ; DI-->LRU extent ;AN000; + jmp Free_Open_Cl_Buffer ; release this extent ;AN000; + +;---------------------------------------------------------------------- +; Mark Previous MRU extent as LRU extent and also connect the previous +; adjucent extent to the next adjcent extent. +;---------------------------------------------------------------------- +Free_Open_Prev_Extn: ; mark previous MRU extent as LRU extnt + mov si, es:[di].EH_Prev_LRU_Ptr ; no - SI-->Previous adj extent + mov es:[si].EH_Next_LRU_Ptr, -1 ;mark previous extent as last extent ;AN000; + + cmp es:[di].EH_Next_Extn_Ptr, -1 ; any next adjucent extent ?? + jne OPen_Join_extents ; yes - join previous to next + + mov si, es:[di].EH_Prev_Extn_Ptr ; no - SI-->Previous adj extent + cmp si, -1 ; any previous adj extent ?? + je Open_Prev_Hdrx ; no - previous is a header + mov es:[si].EH_Next_Extn_Ptr, -1 ; mark previous extent as the last + jmp short Free_Open_Cl_Buffer ; free the current extent + +Open_Prev_Hdrx: + push di ; DI-->extent to be deleted + mov di,LRU_Hdr ; DI-->LRU header + mov es:[di].FH_Next_Extn_Ptr, -1 ; mark header with no extents + mov es:[di].FH_MRU_Extn_Ptr, -1 ; mark header with no extents + pop di + jmp short Free_Open_Cl_Buffer ; free current extent + +Open_Join_Extents: ; DI-->current extent to be freed + mov si, es:[di].EH_Prev_Extn_Ptr ; no - SI-->Previous adj extent + cmp si, -1 ; any previous extent ?? + je Open_Prev_Hdry ; no - previous is a header - join header + ; to extent + mov ax, es:[di].EH_Next_Extn_Ptr ; AX = address of next adjucent extent + mov es:[si].EH_Next_Extn_Ptr,ax ; connect prev adj extent to next adj extent + push di ; save addrs of extent to be deleted + mov di, ax ; SI = address of previous LRU extent + mov es:[di].EH_Prev_Extn_Ptr,si ; address of next LRU extent + pop di ; restore address + jmp short Free_Open_Cl_Buffer ; free the extent + +Open_Prev_Hdry: + mov si, LRU_Hdr ; SI-->LRU_Hdr + mov ax, es:[di].EH_Next_Extn_Ptr ; AX = address of next adjucent extent + mov es:[si].FH_Next_Extn_Ptr,ax ; connect hdr to next adj extent + mov si,ax ; SI = addrss of next adj extent + mov es:[si].EH_Prev_Extn_Ptr,-1 ; mark no previous extent + mov di,LRU_Extent ; DI-->extent to be deleted + +;---------------------------------------------------------------------------- +; Free the current Extent or Header +;---------------------------------------------------------------------------- +Free_Open_Cl_Buffer: ; + mov si,di ; SI-->LRU extent or header ;AN000; + mov di,Drive_Hdr_Ptr ; DI-->drive buffer ;AN000; + mov ax,es:[di].Free_Ptr ;AN000; + mov es:[si].EH_Next_Extn_Ptr,ax ; connect Free ptr to last ;AN000; + ; extent in the queue + mov ax, -2 ; discontinuous mark (-2) ;AN000; + mov es:[si], ax ; mark freed area as discontinuous ;AN000; + mov es:[di].Free_Ptr,si ; connect header or extent to free area ;AN000; + +; Increase the Free_Size entry in Drive Header + mov ax, Size File_Header ; size is same for both header or extent ;AN000; + add es:[di].Free_Size, ax ; update free buffer count ;AN000; + mov Free_Flag,1 ; set flag for discontinuous free area ;AN000; + clc +Free_Exit: ; exit + ret ; return ;AN000; + +FIND_FREE_BUFFER endp + + + + + + +;---------------------------------------------------------------------- +; PROCEDURE: Make_MRU_Header +; +; FUNCTION: Move header to the top of the queue. If the header is at the +; bottom of the queue, mark previous header as LRU header +; before moving the header to the top of the queue. +; +; INPUT: Drive_Hdr_Ptr - Points to drive header +; Cur_Hdr_Ptr - Points to current header +; ES--> Cache Buffer Segment +; +; OUTPUT: Header is moved to top of the current queue +; SI-->current header +; +;---------------------------------------------------------------------- + +MAKE_MRU_HEADER PROC NEAR + + mov si,Cur_Hdr_Ptr ; SI-->Current Header ;AN000; + cmp es:[si].FH_Next_Hdr_Ptr,-1 ; current header LRU header ;AN000; + jne Move_close_gap ; no, jump ;AN000; + ;AN000; + mov di,Prev_Hdr_Ptr ; yes, make previous header + mov es:[di].FH_Next_Hdr_Ptr,-1 ; LRU header ;AN000; + jmp short move_to_top + +Move_Close_Gap: + mov di,Prev_Hdr_Ptr ; yes, get previous header + mov ax,es:[si].FH_Next_Hdr_Ptr ; get next header address + mov es:[di].FH_Next_Hdr_Ptr,ax ; connect previous hdr to next hdr + ;AN000; +Move_To_Top: + mov di,drive_Hdr_Ptr ; DI-->drive buffer ;AN000; + mov ax,es:[di].MRU_Hdr_Ptr ; connect current header to ;AN000; + mov es:[si].FH_Next_Hdr_Ptr,ax ; previous MRU header ;AN000; + mov es:[di].MRU_Hdr_Ptr,si ; make current header MRU hdr ;AN000; + ; + ret + +Make_MRU_Header ENDP + + + + + + +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +; PROCEDURE: MAKE_MRU_EXTENT +; +; FUNCTION: Move Extent to the top of the queue. If the extent is at the +; bottom of the queue, mark previous extent as LRU extent +; before moving the extent to the top of the queue. If the extent +; is between first and last, then close the MRU-LRU chain gap. +; If the extent is already MRU then exit. +; +; This routine is called if clusters are inserted or looked up +; from an existing extent. +; +; INPUT: Cur_Hdr_Ptr - Address of current header +; Cur_Extn_Ptr - Address of current extent +; ES--> Cache Buffer Segment +; +; OUTPUT: Extent is moved next to the current header +; SI-->current extent +; +;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +MAKE_MRU_EXTENT PROC NEAR + + mov si,Cur_Hdr_Ptr ; SI-->Current Header ;AN000; + mov ax,Cur_Extn_Ptr + cmp es:[si].FH_MRU_Extn_Ptr, ax ; current extent already MRU?? ;AN000; + je Make_MRU_Exit ; yes - exit + + mov si, Cur_Extn_Ptr ; SI-->Current extent + mov di,es:[si].EH_Prev_LRU_Ptr ; get address of previous MRU extent + cmp di, -1 ; any previous MRU extent ?? + je Make_MRU_Exit ; none - exit- current extent is already MRU + +; Close the gap (connect previous to next extent) + mov si, Cur_Extn_Ptr + cmp es:[si].EH_Next_LRU_Ptr, -1 ; current extent LRU extent ?? + jne join_the_gap ; no - close the gap + mov es:[di].EH_Next_LRU_Ptr, -1 ; mark the previous extent MRU + jmp short move_MRU_Extent ; make mru extent + +Join_The_Gap: + mov ax, es:[si].EH_Next_LRU_Ptr ; AX-->next LRU extent + mov es:[di].EH_Next_LRU_Ptr,ax ; connect previous to next + mov bx,di ; BX-->prev LRU extent + mov di,ax ; DI-->Next LRU extent + mov es:[di].EH_Prev_LRU_Ptr, bx ; set previous LRU extent address + + +; Make the current extent MRU extent +Move_MRU_Extent: + mov di,Cur_Hdr_Ptr ; DI-->Current header + mov ax,es:[di].FH_MRU_Extn_Ptr ; AX-->Previous MRU extent + mov es:[si].EH_NEXT_LRU_Ptr,ax ; connect previous to current extent + mov es:[di].FH_MRU_Extn_Ptr,si ; make current extent MRU extent + mov es:[si].EH_Prev_LRU_Ptr, -1 ; mark no previous LRU extent + + mov di,ax ;(12/29) set prev LRU addrs of prev MRU extent + mov es:[di].EH_Prev_LRU_Ptr,si ;(12/29) + +Make_MRU_Exit: + clc + ret ; return + +MAKE_MRU_EXTENT ENDP + + + + + + +;---------------------------------------------------------------------- +; PROCEDURE: JOIN_PREV_TO_NEXT +; +; FUNCTION: Connect previous header to next header inorder to close the +; gap created when a header is moved to top of the Queue or to +; the top of CLOSE queue. If the file header is the first header +; under the current Drive header, connect header to the MRU_Hdr_Ptr. +; +; INPUT: Prev_Hdr_Ptr - Points to Previous header +; Cur_Hdr_Ptr - Points to Current Header +; Queue_Type - Queue Type: 0 = Open Queue +; 1 = Close Queue +; ES--> Cache Buffer Segment +; OUTPUT: Gap is closed +; +;---------------------------------------------------------------------- + +JOIN_PREV_TO_NEXT PROC + + cmp Prev_Hdr_Ptr, -1 ; current hdr first file header ?? ;AN000; + jne join_prev_hdr ; no, close gap ;AN000; + +; Yes, in this case close gap by connecting Drive header to next header + mov di,Drive_Hdr_Ptr ; DI-->drive header ;AN000; + mov si,Cur_Hdr_Ptr ; SI-->Current header ;AN000; + mov ax,es:[si].FH_Next_Hdr_Ptr ; AX-->Next Header ;AN000; + cmp Queue_Type, 1 ; Is this Close Queue ?? ;AN000; + je Join_Sel_Close_Ptr ; Yes, jump ;AN000; + mov es:[di].MRU_Hdr_Ptr,ax ; join next header to Drive Header ;AN000; + jmp short join_exit ; exit ;AN000; + +Join_Sel_Close_Ptr: + mov es:[di].Close_Ptr,ax ; join next header to Drive Header ;AN000; + jmp short join_exit ; exit ;AN000; + + +; Connect previous header to next header ( close the gap ) +Join_Prev_Hdr: + mov di,Prev_Hdr_Ptr ; DI-->Previous header ;AN000; + mov si,Cur_Hdr_Ptr ; SI-->Current Header ;AN000; + mov ax,es:[si].FH_Next_Hdr_Ptr ; connect previous header ;AN000; + mov es:[di].FH_Next_Hdr_Ptr,ax ; to next header ;AN000; + +Join_Exit: + ret ; exit ;AN000; + +JOIN_PREV_TO_NEXT ENDP + + + + + + +;---------------------------------------------------------------------- +; PROCEDURE: UPDATE_FREE_AREA +; +; FUNCTION: Update Free area pointer and Free area size before creating +; a new extent or new header +; +; INPUT: Prev_Hdr_Ptr - Points to Previous header +; Cur_Hdr_Ptr - Points to Current Header +; Queue_Type - Queue Type: 0 = Open Queue +; 1 = Close Queue +; Free_Flag - Free area type: 0 = continous free area +; 1 = non-contiguous free area +; ES--> Cache Buffer Segment +; +; +; OUTPUT: Free pool address and size is updated +; +;---------------------------------------------------------------------- + +UPDATE_FREE_AREA PROC + + mov di,Drive_Hdr_Ptr ; DI-->drive header ;AN000; + mov si,es:[di].Free_Ptr ; SI-->current free pointerted ;AN000; + ; + mov ax, Size Extent_Header ;AN000; + sub es:[di].Free_Size, ax ; update free area size ;AN000; + + cmp Free_Flag, 1 ; continuous free area ?? ;AN000; + jne ext_add_free_ptr ; yes - update free area pointer ;AN000; + +;---------------------------------------------------------------------- +; If discontinuous Free area. Update the Free pointer by getting pointer +; to next free from the 4th word using header or extent structure. +; This is because the discontinuous areas are connected chained through +; the 4th word +;---------------------------------------------------------------------- + mov ax,es:[si].FH_Next_Hdr_Ptr ; no, update FREE area pointer ;AN000; + mov es:[di].Free_Ptr,ax ; using the Header structure ;AN000; + jmp short Update_Free_Exit ; Exit ;AN000; + +;---------------------------------------------------------------------- +; If continuous Free area. Next free area address is computed by adding +; the size of extent of header structure. +;---------------------------------------------------------------------- +Ext_Add_Free_Ptr: + mov ax, size File_Header ; calculate the address of ;AN000; + add es:[di].Free_Ptr,ax ; next free area by adding size of ;AN000; + ; a extent or header. Both same size +Update_Free_Exit: + ret ; exit ;AN000; + +UPDATE_FREE_AREA ENDP + + + + +;---------------------------------------------------------------------- +; Procedure: CHECK_IT Checks the validity of the queues +; +;---------------------------------------------------------------------- + +CHECK_IT PROC NEAR + + pushf ; save all registers + push bx + push di + cmp check_flag,0 + je check_exit + mov ah,090h + xor al,al + xor cx,cx + mov cl,func_cod + mov di, Drive_Hdr_Ptr + INT 2FH +check_exit: + pop di + pop bx + popf + ret + +CHECK_IT ENDP + + + +; Calculate the size of the Cseg_Seek module in bytes + IF ($-Cseg_Seek) MOD 16 ;AN000; + ORG ($-Cseg_Seek)+16-(($-Cseg_Seek) MOD 16) ;AN000; + ENDIF ;AN000; +END_SEEK label word + + +CSEG_SEEK ENDS + END diff --git a/v4.0/src/CMD/FASTOPEN/FASTSEGS.INC b/v4.0/src/CMD/FASTOPEN/FASTSEGS.INC new file mode 100644 index 0000000..fd6c46d --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTSEGS.INC @@ -0,0 +1,20 @@ + + + +.seq +stack segment Stack 'STACK' ; represents STACK ;AN000; +stack ends ;AN000; + +cseg_main segment Public 'CODE'; represents MAIN +cseg_main ends + +cseg_open segment Public 'CODE'; represents FASTOPEN ;AN000; +cseg_open ends ;AN000; + +cseg_seek segment Public 'CODE'; represents FASTSEEK ;AN000; +cseg_seek ends ;AN000; + +cseg_init segment Public 'CODE' ; represents INIT +cseg_init ends + + \ No newline at end of file diff --git a/v4.0/src/CMD/FASTOPEN/FASTSM.ASM b/v4.0/src/CMD/FASTOPEN/FASTSM.ASM new file mode 100644 index 0000000..b2dad14 --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/FASTSM.ASM @@ -0,0 +1,145 @@ + PAGE 90,132 ;A2 + TITLE fastsm.SAL - fastopen SYSTEM MESSAGES +;****************** START OF SPECIFICATIONS ***************************** +; MODULE NAME: fastsm.SAL + +; DESCRIPTIVE NAME: Include the DOS system MESSAGE HANDLER in the SEGMENT +; configuration expected by the modules of fastopen. + +;FUNCTION: The common code of the DOS SYSTEM MESSAGE HANDLER is made a +; part of the fastopen module by using INCLUDE to bring in the +; common portion, in SYSMSG.INC. This included code contains +; the routines to initialize for message services, to find +; where a particular message is, and to display a message. + +; ENTRY POINT: SYSDISPMSG:near +; SYSGETMSG:near +; SYSLOADMSG:near + +; INPUT: +; AX = MESSAGE NUMBER +; BX = HANDLE TO DISPLAY TO (-1 means use DOS functions 1-12) +; SI = OFFSET IN ES: OF SUBLIST, OR 0 IF NONE +; CX = NUMBER OF %PARMS, 0 IF NONE +; DX = CLASS IN HIGH BYTE, INPUT FUNCTION IN LOW +; CALL SYSDISPMSG ;DISPLAY THE MESSAGE + +; If carry set, extended error already called: +; AX = EXTENDED MESSAGE NUMBER +; BH = ERROR CLASS +; BL = SUGGESTED ACTION +; CH = LOCUS +; _ _ _ _ _ _ _ _ _ _ _ _ + +; AX = MESSAGE NUMBER +; DH = MESSAGE CLASS (1=DOS EXTENDED ERROR, 2=PARSE ERROR, -1=UTILITY MSG) +; CALL SYSGETMSG ;FIND WHERE A MSG IS + +; If carry set, error +; CX = 0, MESSAGE NOT FOUND +; If carry not set, ok, and resulting regs are: +; CX = MESSAGE SIZE +; DS:SI = MESSAGE TEXT +; _ _ _ _ _ _ _ _ _ _ _ _ + +; CALL SYSLOADMSG ;SET ADDRESSABILITY TO MSGS, CHECK DOS VERSION +; If carry not set: +; CX = SIZE OF MSGS LOADED + +; If carry is set, regs preset up for SYSDISPMSG, as: +; AX = ERROR CODE IF CARRY SET +; AX = 1, INCORRECT DOS VERSION +; DH =-1, (Utility msg) +; OR, +; AX = 1, Error loading messages +; DH = 0, (Message manager error) +; BX = STDERR +; CX = NO_REPLACE +; DL = NO_INPUT + +; EXIT-NORMAL: CARRY is not set + +; EXIT-ERROR: CARRY is set +; Call Get Extended Error for reason code, for SYSDISPMSG and +; SYSGETMSG. + +; INTERNAL REFERENCES: +; ROUTINES: (Generated by the MSG_SERVICES macro) +; SYSLOADMSG +; SYSDISPMSG +; SYSGETMSG + +; DATA AREAS: + +; INCLUDE SYSMSG.INC ;Permit System Message handler definition +; +; EXTERNAL REFERENCES: +; ROUTINES: none + +; DATA AREAS: control blocks pointed to by input registers. + +; NOTES: + +; To assemble these modules, the alphabetical or sequential +; ordering of segments may be used. + +; For LINK instructions, refer to the PROLOG of the main module, +; fastopen.asm. + +; REVISION HISTORY: A000 Version 4.00: add PARSER, System Message Handler, +; +; COPYRIGHT: "MS DOS FASTOPEN Utility" +; "Version 4.00 (C)Copyright 1988 Microsoft " +; "Licensed Material - Property of Microsoft " +; +;****************** END OF SPECIFICATIONS ***************************** + IF1 ; ;AN000; + %OUT COMPONENT=fastopen, MODULE=fastsm.asm... + ENDIF ; ;AN000; +; = = = = = = = = = = = = + +HEADER MACRO TEXT ;; ;AN000; +.XLIST ;; + SUBTTL TEXT +.LIST ;; + PAGE ;; ;AN000; + ENDM ;; ;AN000; +; = = = = = = = = = = = = + INCLUDE SYSMSG.INC ;PERMIT SYSTEM MESSAGE HANDLER DEFINITION ;AN000; + MSG_UTILNAME ;IDENTIFY THE COMPONENT ;AN000; +; = = = = = = = = = = = = + HEADER ; ;AN000; +CSEG_INIT SEGMENT PARA PUBLIC 'CODE' ; + ASSUME CS:CSEG_INIT ;ESTABLISHED BY CALLER + ASSUME DS:CSEG_INIT ;ESTABLISHED BY CALLER + ASSUME ES:CSEG_INIT ;ESTABLISHED BY CALLER + + PUBLIC COPYRIGHT ; ;AN000; +COPYRIGHT DB "MS DOS FASTOPEN Utility " ; ;AN000; + INCLUDE COPYRIGH.INC ; ;AN000; + HEADER ; ;AN000; + MSG_SERVICES ;WORKAREAS FOR SYSTEM MESSAGE HANDLER ;AN000; +; = = = = = = = = = = = = + HEADER ; ;AN000; + PUBLIC SYSLOADMSG ; ;AN000; + PUBLIC SYSDISPMSG ; ;AN000; + + + MSG_SERVICES ; + + ;DEFAULT=CHECK DOS VERSION + ;DEFAULT=NEARmsg + ;DEFAULT=INPUTmsg + ;DEFAULT=NUMmsg + ;DEFAULT=NO TIMEmsg + ;DEFAULT=NO DATEmsg + +.xlist +.xcref + MSG_SERVICES ;AN000; + include msgdcl.inc +.cref +.list +; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +CSEG_INIT ENDS ; + END ; ;AN000; diff --git a/v4.0/src/CMD/FASTOPEN/MAKEFILE b/v4.0/src/CMD/FASTOPEN/MAKEFILE new file mode 100644 index 0000000..8911afe --- /dev/null +++ b/v4.0/src/CMD/FASTOPEN/MAKEFILE @@ -0,0 +1,47 @@ +#************************** makefile for cmd\... *************************** + +msg =..\..\messages +dos =..\..\dos +inc =..\..\inc +hinc =..\..\h + +# +####################### dependencies begin here. ######################### +# + +all: fastopen.exe + +fastopen.ctl: fastopen.skl makefile $(msg)\$(COUNTRY).msg + +fastopen.obj: fastopen.asm $(inc)\fastopen.inc \ + makefile + +fastseek.obj: fastseek.asm $(inc)\fastopen.inc \ + makefile + +fastinit.obj: fastinit.asm $(inc)\dossym.inc $(inc)\fastopen.inc \ + makefile + +fastp.obj: fastp.asm \ + makefile \ + $(inc)\psdata.inc \ + $(inc)\parse.asm + +fastsm.obj: fastsm.asm \ + makefile \ + $(inc)\versiona.inc \ + $(inc)\copyrigh.inc \ + $(inc)\sysmsg.inc \ + $(inc)\msgserv.asm \ + fastopen.ctl \ + fastopen.cl1 \ + fastopen.cl2 \ + fastopen.cla \ + +fastopen.exe: fastopen.obj \ + fastopen.lnk \ + fastseek.obj \ + fastinit.obj \ + fastp.obj \ + fastsm.obj + link @fastopen.lnk -- cgit v1.2.3