MFS Shell Examples Please --] Cam Purdy (OpenInsight)
At 13 JUL 2000 06:38:16PM Richard Bright wrote:
I'm working on a very simple MFS to control security - to restrict display of selected fields in a record based on User security and Field Rights as stored in a field in the same record. I have the logic working however I want verify that I am properly handling each of the GoSub CODE values for the MFS subroutine ie which CODE values do I pass on to Next.MFS, what ones do I set STATUS False$ /True$ ?
I am using the two standard OI MFS inserts - the equates and GoSub. Yes, I have the MFS PDF and AREV Tech Manual but this info appears slightly dated v my OIv3.71 equates eg which refers to select.index etc and replaces lock.semaphore with Reserved.
1. Could you email me the sample MFS shells.
2. Are there any other good MFS examples which you or others could provide? I am most interested in some of the cool things that one can do with MFS eg controlling select lists to filter out "restricted" records, audit trails and record_change trails. Also the possibility of maintaining custom indexes for quick retrieval akin to Quickdex for fields other than key etc
Richard Bright
At 15 JUL 2000 07:47PM Cameron Purdy wrote:
I want verify that I am properly handling each of the GoSub CODE values for the MFS subroutine ie which CODE values do I pass on to Next.MFS, what ones do I set STATUS False$ /True$ ?
There are three that you do NOT next-fs on: Install, Flush, and UnlockAll.
Be careful on Install. The system may not have finished starting up by that time so you are limited in what you can do.
Remember that your MFS runs in a very strict file-io context. Don't do any PS calls for example (get/set properties).
I am using the two standard OI MFS inserts - the equates and GoSub. Yes, I have the MFS PDF and AREV Tech Manual but this info appears slightly dated v my OIv3.71 equates eg which refers to select.index etc and replaces lock.semaphore with Reserved.
Use the OI one if possible. You most probably will not be implementing the .index stuff anyway.
1. Could you email me the sample MFS shells.
You are in luck. Apparently I did just that for someone else because I had the following code hanging around:
<code> subroutine Log_MFS(Code, BFS, Handle, Name, Fmc, Record, Status) ***************************************************************************** * * Name : Log_MFS * Description: Logs changes to records in various tables * * History (Date, Initials, Notes) * 05/13/97 cp Original programmer (XQ_MFS). * ***************************************************************************** $insert Logical $insert FSErrors_100 equ MFS_NAME$ to "LOG_MFS" $insert File.System.OnGosub return **************************************** * store file name in the returned handle **************************************** Open.File: Table =Name 1,"*" FSHandle=Handle gosub NextFS if Status then Record := "*": Table end return ************************** * record is being modified ************************** Write.Record: Table =Handle -1,"B*" FSHandle=Handle 1,col1()-1 gosub NextFS if Status then gosub LogWrite end return ************************* * record is being deleted ************************* Delete.Record: Table =Handle -1,"B*" FSHandle=Handle 1,col1()-1 gosub NextFS if Status then gosub LogDelete end return ********************************* * log transaction for all records ********************************* ClearFile: Status =TRUE$ Table =Handle -1,"B*" FSHandle=Handle 1,col1()-1 FSList =delete(BFS, 1, 1, 1) fTable =FSList: @vm: FSHandle select fTable eof=FALSE$ transfer Name to HoldName loop readnext Name else eof=TRUE$ until eof gosub LogDelete while Status repeat transfer HoldName to Name if Status then gosub NextFS end return ********************************* * non-chained filing system calls ********************************* Flush: Unlock.All: Record=" Install: Status=TRUE$ return ***************************** * chained filing system calls ***************************** Read.Record: ReadO.Record: Lock.Record: Unlock.Record: Select: ReadNext: ClearSelect: Record.Count: Create.Index: Delete.Index: Update.Index: Select.Index: ReadNext.Index: Omni.Script: Table =Handle -1,"B*" FSHandle=Handle 1,col1()-1 gosub NextFS return Reserved: @file.error=FS_NOT_IMPL$: @fm: Code: @fm: MFS_NAME$ Status=FALSE$ return Create.File: Rename.File: Move.File: Delete.File: Remake.File: Open.Media: Create.Media: Read.Media: Write.Media: Close.Media: FSHandle=Handle gosub NextFS return ***************************** * execute filing system chain ***************************** NextFS: FSList=delete(BFS, 1, 1, 1) NextFS=FSList if len(NextFS) then call @NextFS(Code, FSList, FSHandle, Name, Fmc, Record, Status) end return ****************************************************************************** ************************* * log record modification ************************* LogWrite: gosub GetOrigRecord begin case case Table=INVOICES" if Record # OrigRecord then * do change processing here end case Table=PURCHASE_ORDERS" if Record # OrigRecord then * do change processing here end end case return ********************* * log record deletion ********************* LogDelete: gosub GetOrigRecord * see LogWrite above for an example return *********************** * load "current" record *********************** * Name in - record key * OrigRecord out - original record or null GetOrigRecord: FSList=delete(BFS, 1, 1, 1) NextFS=FSList call @NextFS(READ.RECORD, FSList, FSHandle, Name, "", OrigRecord, Exists) if Exists else OrigRecord=" end return</code>
2. Are there any other good MFS examples which you or others could provide? I am most interested in some of the cool things that one can do with MFS eg controlling select lists to filter out "restricted" records, audit trails and record_change trails. Also the possibility of maintaining custom indexes for quick retrieval akin to Quickdex for fields other than key etc
Here's one that collates together multiple source files into a virtual SYSPROCS for our GOLD source system:
<code> subroutine IT_SysProcs_Mfs(Code, BFS, Handle, Name, Fmc, Record, Status) ***************************************************************************** * * Name : IT_SysProcs_Mfs * Description: Modified Filing System for OpenInsight "Gold" SysProcs table * * History (Date, Initials, Notes) * 10/21/97 cp Original programmer. * ***************************************************************************** $insert Logical $insert FSErrors_100 equ MFS_NAME$ to "IT_SYSPROCS_MFS" common //MFS_NAME$// f_Arev_BP, f_Rev_BP, f_Rev_Hidden, f_Rev_Procs, f_Notes_Procs $insert File.System.OnGosub return **************************** * open other required tables **************************** Open.File: Status=TRUE$ open "AREV_BP" to f_Arev_BP else Status=FALSE$ open "REV_BP" to f_Rev_BP else Status=FALSE$ open "REV_HIDDEN" to f_Rev_Hidden else Status=FALSE$ open "REV_PROCS" to f_Rev_Procs else Status=FALSE$ open "NOTES_PROCS" to f_Notes_Procs else Status=FALSE$ if Status then gosub NextFS end return ******************************* * unchained filing system calls ******************************* ReadO.Record: Read.Record: gosub NextFS if not(Status) and @file.error=FS_REC_DNE$ then [email protected] Hold_Status =status() Exists =" Tables =REV_BP": @fm: "REV_HIDDEN" : @fm: "NOTES_PROCS": @fm: "REV_HIDDEN" : @fm: "REV_PROCS": @fm: "REV_HIDDEN" : @fm: "AREV_BP": @fm: "REV_HIDDEN" Handles=f_Rev_BP: @fm: f_Rev_Hidden : @fm: f_Notes_Procs: @fm: f_Rev_Hidden : @fm: f_Rev_Procs: @fm: f_Rev_Hidden : @fm: f_Arev_BP: @fm: f_Rev_Hidden Keys =Name : @fm: "REV_BP/": Name: @fm: Name : @fm: "OINOTES_SYSPROCS/": Name: @fm: Name : @fm: "OE_SYSPROCS/": Name: @fm: Name : @fm: "AREV.BP/": Name cKeys =count(Keys, @fm) + (Keys # "") dim Records(cKeys) * find all copies of the requested record for i=1 to cKeys fTemp=Handles[i] read Temp from fTemp, Keys[i] then Records(i)=Temp Exists[i] =TRUE$ end else Records(i)=" Exists[i] =FALSE$ end next i if index(Exists, TRUE$, 1) then * weed out duplicates for i=1 to cKeys if Exists[i] then Temp=*":Records(i) for j=i+1 to cKeys if "*":Records(j)=Temp then Exists=FALSE$ end next j end next i * determine which record to return; list all different records found First =" Text =**************************************************" Text=*" Text=* This record does not exist in the SYSPROCS table" Text=*" Text=* ": fmt("Table", "L#20"): " Key" Text=* ": str("-", 20): " ": str("-", 20) for i=1 to cKeys if Exists[i] then Text=* ": fmt(Tables[i], "L#20"): " ": Keys[i] if First else First=i Text := " (this record)" end end next i Text=*" Text=**************************************************": @fm: @fm: @fm record =Text: Records(First) status =TRUE$ @file.error=" status() =0 end else @file.error=Hold_AtFileError status() =Hold_Status end end return ******************************* * unchained filing system calls ******************************* Flush: Unlock.All: Record=" Install: Status=TRUE$ return ***************************** * chained filing system calls ***************************** Write.Record: Delete.Record: Lock.Record: Unlock.Record: Select: ReadNext: ClearSelect: Record.Count: Create.Index: Delete.Index: Update.Index: Select.Index: ReadNext.Index: Omni.Script: gosub NextFS return ClearFile: Reserved: @file.error=FS_NOT_IMPL$: @fm: Code: @fm: MFS_NAME$ Status=FALSE$ return Create.File: Rename.File: Move.File: Delete.File: Remake.File: Open.Media: Create.Media: Read.Media: Write.Media: Close.Media: gosub NextFS return ***************************** * execute filing system chain ***************************** NextFS: FSList=delete(BFS, 1, 1, 1) NextFS=FSList if len(NextFS) then call @NextFS(Code, FSList, Handle, Name, Fmc, Record, Status) end return</code>
Cameron Purdy
Revelation Software
At 16 JUL 2000 05:32AM Richard Bright wrote:
Cam,
Thanks for the MFS code. While I had the MFS working fine (thusfar) I am pleased to clarify some of the issues plus your code expanded / filled in some gaps.
I forgot to ask if there are general rules for where the MFS should be installed in the MFS / BFS chain (depending on the nature of the MFS. That is, the manual suggests that a simple MFS such as handling field level security (blanking out field) is installed at the beginning of the chain. But presumably the SI.MFS will come first, and the BFS/RTP57 comes last ie
SI.MFS MY_TABLE_MFS*MYAPP RTP57
Richard Bright
At 16 JUL 2000 01:36PM Cameron Purdy wrote:
You can solve that question simply by asking the question: should SI.MFS see the data before or after you filter it. I would assume (in most cases) that you would want SI.MFS to see the data BEFORE you start whacking it on a user-by-user basis, since otherwise your indexes will be crap.
Cameron Purdy
Revelation Software
At 17 JUL 2000 11:50AM Paul Simonsen wrote:
Hello all,
I was looking through Cameron's MFS code to see if I was missing anything in our audit MFS. For those who will be venturing into the world of MFS, pay careful attention to Cameron's code regarding Record.Count and Clearfile. The MFS pdf documentation does not list these items as needing to have the file name removed from the handle before continuing to the next FS.
I also have a question regarding the *.Index operations. I haven't found any documentation on these but noticed they require the file name being removed from the handle as well. I have updated our MFS logic, but I haven't ever encountered a problem with this before.
Is there any documentation on these operations?
At 17 JUL 2000 12:41PM [url=http://www.sprezzatura.com]The Sprezzatura Group[/url] wrote:
The issue is really one of semantics here. Technically, nothing should be removed from the handle except what the MFS itself puts there. Each MFS should pass the handle back as it found it. For example, a common practive in some MFSs is to place the file name in the handle so a program has easy access to the file name. There is nothing wrong with this practice, provided the MFS remembers to remove the name before calling @NEXTFS.
Cameron is relying on a bit of trickery, which will not always work, (sorry Cam, you know I rarely try to correct you). Since your MFS can theoretically be anywhere on the FS chain, the handle can be in any format. Cameron is relying on knowing his system, what MFSs are available, what structure they are using and what version of ARev or OI he is running.
This touches on the other issue in dealing with handles inside an MFS. Revelation has occasionally changed the structure of the handle as returned from RTP57 and various system MFSs (SI.MFS and QUICKDEX.MFS come to mind). MFSs which make assumptions about the structure of the handle could break on different versions of ARev or OI.
So, back to Cameron's program. What he's doing in the ClearFile section is attempting to clear out the various log records created for each record in the base file. To do that, he needs to process each record in the base file before the file is cleared. So, he's performing a simple R/BASIC select to obtain all the record keys.
A simple R/BASIC select requires a valid handle for processing. This means Cameron has two options. He can either re-open the file to obtain the "correct" handle or he can use his superior knowledge of the system to generate a valid simple handle.
The safest course of action is to open the file. The fastest file access would be to generate a simple handle.
In general though, unless you want access to the current file from within the MFS, you should never have to manipulate the current handle.
I'll be happy to elaborate further if you wish. MFSs just might be my favourite subject to pontificate on.
World leaders in all things RevSoft
At 17 JUL 2000 01:27PM Cameron Purdy wrote:
Well Mr. Sprezzatura Group,
Even with the threat of pontification looming large I would point out that the filename-in-the-handle-thing and removing it as the code did should work well, because each MFS (both the one you write and the ones outside of yours in the chain) MUST provide the inner FS with the handle that the inner FS returned from OPEN.FILE. In other words, the code I wrote MUST remove the filename from the handle because it added it to the handle returned from the inner FS's OPEN.FILE call. As long as everyone obeys the rules, it works beautifully. That said, I have seen some cases where file handle composition was assumed to be in a particular format and was thus parsed directly assuming that no MFS had added information to it. Those cases, BTW, are where OMNI.SCRIPT is supposed to be used, since you can ask the FS a question specific to that FS without having to know anything about the handle structure, and the outer MFS's are supposed to pass the questions down that are not intended for them. At least that is ho
w I remember it.
Cameron Purdy
Revelation Software
At 17 JUL 2000 04:22PM Richard Bright wrote:
Cam,
Thanks for confirming the issue of 'place of MFS in chain'. Also Sprez's discussion of manipulation of the file handle has been most interesting. Working off your Log example code I had been hesitant, not knowing the end purpose of the handle manipulation and so had eliminated it from my MFS re-write. I will now revisit this issue and look to see if I can exploit that feature. The big plus - is now understanding WHY the extra code is there.
Richard Bright