You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

An MFS may occasionally require access to a file while it is processing. For example, many applications require read-before-write verification. As another example, an audit trail MFS will need to write its audit information to an audit file.

There are two options for accessing files from within an MFS.

  • Access files directly, by using MFS calls.

  • Execute BASIC+ file I/O commands such as READ and WRITE.

Different circumstances dictate the choice of one option or another. Briefly stated, direct calls are necessary when accessing the current file -- the file for which the MFS has trapped a file operation. Access to files other than the current file is best handled using BASIC+ commands.

Accessing the Current File

If the MFS requires access to the current file, it should generally not generate an BASIC+ command to access the file. When an MFS uses BASIC+ commands to access a current file, those BASIC+ commands result in calls back to the same MFS.

In some instances, this can result in an infinite loop as the MFS processes these MFS-generated I/O calls. A good example is an MFS that spawns modified versions of the current call. For instance, a programmer might write an MFS that monitors record deletions in a programs file. When a delete is detected, the MFS spawns additional deletes to clean up the object code ($ records). If the MFS were to use BASIC+ commands, each subsequent DELETE would call the same MFS, which would spawn additional DELETE commands, etc.

Instead of using BASIC+ commands, the MFS can generate direct calls to the next MFS or the BFS. The following code fragment illustrates how an MFS might execute read-before-write logic using direct calls to the next filing system.  Note that the MFS must preserve any values that might be changed by the direct call (such as the value of the RECORD argument).

 

WRITE.RECORD:
* read-before-write logic here
READ.RECORD = 1
OLD.RECORD = ''
NEXTFS = BFS<1,1,2>
CALL @NEXTFS(READ.RECORD, FS, HANDLE,NAME, FMC, OLD.RECORD, STATUS)
IF STATUS THEN
  IF OLD.RECORD NE RECORD THEN
    CALL MSG(@window, "Record ":NAME:" has changed.")
  END ELSE
    CALL MSG(@window, "Record ":NAME:" has not changed.")
  END
END ELSE
  CALL MSG(@window, "Record ":NAME:" is a new record.")
END
* continue normal processing
GOSUB NEXT.MFS
RETURN

Accessing Different Files

If the MFS needs to update a file other than the current file, it is best to use BASIC+ file I/O commands (OPEN, READ, WRITE, DELETE) rather than a direct call. If a direct call is used, the MFS will pass a call to the next filing system (MFS or BFS) for the current file. This may cause problems in two ways.

  • First, the MFS that follows the current MFS may be installed for only the current file, and not for other files. A direct call might thus inadvertently "install" the next MFS onto the second file being accessed.

  • Another problem is the converse of the first. By doing a direct call using the MFS list for the current file, an MFS may bypass the MFS list for the second file. For example, if an MFS uses a direct call to access a file that is indexed, SI.MFS will not be called unless by chance it appears in the BFS argument for the current file.

  • A corollary to this is that the second file may use an entirely different BFS. Obviously, a direct call from the MFS can only use the BFS for the current file.

Some applications might present a hybrid of these problems.  An MFS might use BASIC+ commands to access a second file, only to discover that the second file also uses the current MFS -- thereby resulting in a call to itself.

Disabling a Function From Within an MFS

One of the roles played by an MFS is that of monitoring specific functions and disabling them under certain circumstances. An example is that of a security MFS that monitors all reads and writes to a file, and permits only authorized users to execute these functions.

The standard method for disabling a function is for the MFS to set the STATUS argument to false, and to execute a RETURN statement immediately. The MFS should normally not call subsequent filing systems, since these may proceed with the operation (such as creating a file or updating a record), reset the value of STATUS, or set the value of other variables used in detecting the success of an operation.

In many cases, the BASIC+ command that generated the MFS call will fall through its ELSE logic when detecting a status of false. This is the case, for instance, for the BASIC+  Read_Row subroutine. Many System Monitor commands will also post a message indicating that the command could not be executed.

The program fragment below illustrates a simple method for disabling the READ.RECORD code:

 

READ.RECORD:
  GOSUB CHECK.SECURITY
  IF SECURITY.CHECK = PASSED$ THEN
    GOSUB NEXT.MFS
  END ELSE
    STATUS = 0
  END
  RETURN

 

 

This method of disabling functions means that a subsequent MFS does not have an opportunity to act upon the code being called. This has implications for the ordering of MFSs. For example, if an audit trail MFS is required to log an attempt to read, write or delete all records -- even if these functions are not successful -- the audit trail MFS must precede any security MFS that might abort the record operation.

Not all functions translate a status value of false directly into a failure. For example, a BASIC+ SELECT statement does not look at the return value of STATUS. Instead, the SELECT statement examines the value of RECORD to determine whether a select condition is active. The value of RECORD is translated into the value of the system variable @LIST.ACTIVE, which is in turn read by subsequent READNEXT statements. If RECORD (and by extension, @LIST.ACTIVE) is false, a READNEXT statement will fall through its ELSE logic.

  • No labels