home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 1 / Mecomp-CD.iso / amiga / tools / system / shutdown / filewatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-23  |  30.5 KB  |  1,364 lines

  1. /*
  2. **    Shutdown 2.0 package, FileWatch.c module
  3. **
  4. **    Copyright © 1992 by Olaf `Olsen' Barthel
  5. **        All Rights Reserved
  6. */
  7.  
  8. #include "ShutdownGlobal.h"
  9.  
  10.     /* The number of patches to install. */
  11.  
  12. #define NUM_PATCHES    (sizeof(PatchTable) / sizeof(struct PatchInfo))
  13.  
  14.     /* The patch table entries look like this. */
  15.  
  16. struct PatchInfo
  17. {
  18.     APTR         NewRoutine;
  19.     LONG         Offset;
  20.     ULONG        *Destination;
  21. };
  22.  
  23.     /* References to write-access routines. */
  24.  
  25. extern ULONG __far     LVOOpen,
  26.              LVOClose,
  27.              LVOWrite,
  28.              LVOFPutC,
  29.              LVOFPuts,
  30.              LVOFWrite,
  31.              LVOVFPrintf,
  32.              LVOVFWritef,
  33.              LVOPutStr,
  34.              LVOWriteChars,
  35.              LVOVPrintf;
  36.  
  37.     /* The original routine vectors. */
  38.  
  39. BPTR            (* __asm OldOpen)(register __d1 STRPTR Name,register __d2 LONG Mode,register __a6 struct DosLibrary *DOSBase);
  40. LONG            (* __asm OldClose)(register __d1 BPTR Handle,register __a6 struct DosLibrary *DOSBase);
  41. LONG            (* __asm OldWrite)(register __d1 BPTR Handle,register __d2 APTR Buffer,register __d3 LONG Length,register __a6 struct DosLibrary *DOSBase);
  42. LONG            (* __asm OldFPutC)(register __d1 BPTR FileHandle,register __d2 UBYTE Char,register __a6 struct DosLibrary *DOSBase);
  43. LONG            (* __asm OldFPuts)(register __d1 BPTR FileHandle,register __d2 STRPTR Buffer,register __a6 struct DosLibrary *DOSBase);
  44. LONG            (* __asm OldFWrite)(register __d1 BPTR FileHandle,register __d2 STRPTR Buffer,register __d3 ULONG BlockLen,register __d4 ULONG Blocks,register __a6 struct DosLibrary *DOSBase);
  45. LONG            (* __asm OldVFPrintf)(register __d1 BPTR FileHandle,register __d2 STRPTR Format,register __d3 LONG *Args,register __a6 struct DosLibrary *DOSBase);
  46. LONG            (* __asm OldVFWritef)(register __d1 BPTR FileHandle,register __d2 STRPTR Format,register __d3 LONG *Args,register __a6 struct DosLibrary *DOSBase);
  47. LONG            (* __asm OldPutStr)(register __d1 STRPTR Buffer,register __a6 struct DosLibrary *DOSBase);
  48. LONG            (* __asm OldWriteChars)(register __d1 STRPTR Buffer,register __d2 ULONG Len,register __a6 struct DosLibrary *DOSBase);
  49. LONG            (* __asm OldVPrintf)(register __d1 STRPTR Format,register __d2 LONG *Args,register __a6 struct DosLibrary *DOSBase);
  50.  
  51.     /* The routines to interface between us and the world out there. */
  52.  
  53. extern BPTR __asm    NewOpen(register __d1 STRPTR Name,register __d2 LONG Mode);
  54. extern LONG __asm    NewClose(register __d1 BPTR Handle);
  55. extern LONG __asm    NewWrite(register __d1 BPTR Handle,register __d2 APTR Buffer,register __d3 LONG Length);
  56. extern LONG __asm    NewFPutC(register __d1 BPTR FileHandle,register __d2 UBYTE Char);
  57. extern LONG __asm    NewFPuts(register __d1 BPTR FileHandle,register __d2 STRPTR Buffer);
  58. extern LONG __asm    NewFWrite(register __d1 BPTR FileHandle,register __d2 STRPTR Buffer,register __d3 ULONG BlockLen,register __d4 ULONG Blocks);
  59. extern LONG __asm    NewVFPrintf(register __d1 BPTR FileHandle,register __d2 STRPTR Format,register __d3 LONG *Args);
  60. extern LONG __asm    NewVFWritef(register __d1 BPTR FileHandle,register __d2 STRPTR Format,register __d3 LONG *Args);
  61. extern LONG __asm    NewPutStr(register __d1 STRPTR Buffer);
  62. extern LONG __asm    NewWriteChars(register __d1 STRPTR Buffer,register __d2 ULONG Len);
  63. extern LONG __asm    NewVPrintf(register __d1 STRPTR Format,register __d2 LONG *Args);
  64.  
  65.     /* Our local routines. */
  66.  
  67. BPTR __asm        MyOpen(register __d1 STRPTR Name,register __d2 LONG Mode);
  68. LONG __asm        MyClose(register __d1 BPTR Handle);
  69. LONG __asm        MyWrite(register __d1 BPTR Handle,register __d2 APTR Buffer,register __d3 LONG Length);
  70. LONG __asm        MyFPutC(register __d1 BPTR FileHandle,register __d2 UBYTE Char);
  71. LONG __asm        MyFPuts(register __d1 BPTR FileHandle,register __d2 STRPTR Buffer);
  72. LONG __asm        MyFWrite(register __d1 BPTR FileHandle,register __d2 STRPTR Buffer,register __d3 ULONG BlockLen,register __d4 ULONG Blocks);
  73. LONG __asm        MyVFPrintf(register __d1 BPTR FileHandle,register __d2 STRPTR Format,register __d3 LONG *Args);
  74. LONG __asm        MyVFWritef(register __d1 BPTR FileHandle,register __d2 STRPTR Format,register __d3 LONG *Args);
  75. LONG __asm        MyPutStr(register __d1 STRPTR Buffer);
  76. LONG __asm        MyWriteChars(register __d1 STRPTR Buffer,register __d2 ULONG Len);
  77. LONG __asm        MyVPrintf(register __d1 STRPTR Format,register __d2 LONG *Args);
  78.  
  79.     /* Local routines for this module. */
  80.  
  81. STATIC VOID __regargs    RegisterAccess(BPTR Handle);
  82. STATIC VOID __saveds    ResetCode(VOID);
  83.  
  84.     /* A table of dos.library routines to be patched. */
  85.  
  86. STATIC struct PatchInfo PatchTable[] =
  87. {
  88.     NewOpen,    (LONG)&LVOOpen,        (ULONG *)&OldOpen,
  89.     NewClose,    (LONG)&LVOClose,    (ULONG *)&OldClose,
  90.     NewWrite,    (LONG)&LVOWrite,    (ULONG *)&OldWrite,
  91.     NewFPutC,    (LONG)&LVOFPutC,    (ULONG *)&OldFPutC,
  92.     NewFPuts,    (LONG)&LVOFPuts,    (ULONG *)&OldFPuts,
  93.     NewFWrite,    (LONG)&LVOFWrite,    (ULONG *)&OldFWrite,
  94.     NewVFPrintf,    (LONG)&LVOVFPrintf,    (ULONG *)&OldVFPrintf,
  95.     NewVFWritef,    (LONG)&LVOVFWritef,    (ULONG *)&OldVFWritef,
  96.     NewPutStr,    (LONG)&LVOPutStr,    (ULONG *)&OldPutStr,
  97.     NewWriteChars,    (LONG)&LVOWriteChars,    (ULONG *)&OldWriteChars,
  98.     NewVPrintf,    (LONG)&LVOVPrintf,    (ULONG *)&OldVPrintf
  99. };
  100.  
  101.     /* The devices we want to ignore for now. Some operate on
  102.      * ram only and are unlikely to get corrupted, some are
  103.      * handled indirectly by the DevWatch.c module.
  104.      */
  105.  
  106. STATIC STRPTR Ignored[] =
  107. {
  108.     "fmsdisk.device",
  109.     "hardfile.device",
  110.     "ramdisk.device",
  111.     "ramdrive.device",
  112.     "asdg.vdisk.device",
  113.     "static.device",
  114.     NULL
  115. };
  116.  
  117.     /* Keyboard reset handler data. */
  118.  
  119. STATIC struct MsgPort        *KeyboardPort;
  120. STATIC struct IOStdReq        *KeyboardRequest;
  121. STATIC struct Interrupt        *KeyboardReset;
  122.  
  123.     /* Number of tasks/processes to use our modified
  124.      * routines and the approriate access semaphore.
  125.      */
  126.  
  127. STATIC struct SignalSemaphore     UseCountSemaphore;
  128. STATIC ULONG             UseCount = 0;
  129.  
  130.     /* Main():
  131.      *
  132.      *    Shutdown handler routine, installs the patches and
  133.      *    watches the keyboard reset.
  134.      */
  135.  
  136. VOID __saveds
  137. Main()
  138. {
  139.         /* Remember the current process identifier. */
  140.  
  141.     HandlerProcess = (struct Process *)SysBase -> ThisTask;
  142.  
  143.         /* Create keyboard reset reply port. */
  144.  
  145.     if(KeyboardPort = CreateMsgPort())
  146.     {
  147.             /* Create keyboard reset request. */
  148.  
  149.         if(KeyboardRequest = CreateIORequest(KeyboardPort,sizeof(struct IOStdReq)))
  150.         {
  151.                 /* Open keyboard.device. */
  152.  
  153.             if(!OpenDevice("keyboard.device",0,KeyboardRequest,0))
  154.             {
  155.                     /* Create the keyboard reset notification interrupt. */
  156.  
  157.                 if(KeyboardReset = (struct Interrupt *)AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC | MEMF_CLEAR))
  158.                 {
  159.                         /* Install the device monitoring wedges. */
  160.  
  161.                     if(WedgeSetup())
  162.                     {
  163.                             /* Set up the keyboard reset handler. */
  164.  
  165.                         KeyboardReset -> is_Node . ln_Name    = HandlerProcess -> pr_Task . tc_Node . ln_Name;
  166.                         KeyboardReset -> is_Code        = (APTR)ResetCode;
  167.  
  168.                             /* Fill in the installation request. */
  169.  
  170.                         KeyboardRequest -> io_Command        = KBD_ADDRESETHANDLER;
  171.                         KeyboardRequest -> io_Data        = (APTR)KeyboardReset;
  172.  
  173.                             /* Install the keyboard reset handler. */
  174.  
  175.                         if(!DoIO(KeyboardRequest))
  176.                         {
  177.                             struct Wedge *WedgeTable;
  178.  
  179.                                 /* Allocate the wedge table. */
  180.  
  181.                             if(WedgeTable = (struct Wedge *)AllocMem(sizeof(struct Wedge) * NUM_PATCHES,MEMF_ANY | MEMF_CLEAR))
  182.                             {
  183.                                     /* Who created use? */
  184.  
  185.                                 if(GlobalBase -> Father)
  186.                                 {
  187.                                     struct FileInfo    *FileInfo,
  188.                                             *NextInfo;
  189.                                     WORD         i;
  190.                                     BYTE         Terminated = FALSE;
  191.                                     ULONG         SignalSet;
  192.  
  193.                                         /* Set up the access count semaphore. */
  194.  
  195.                                     InitSemaphore(&UseCountSemaphore);
  196.  
  197.                                         /* Open the catalog file. */
  198.  
  199.                                     LocaleOpen("shutdown.catalog","english");
  200.  
  201.                                         /* Make ourselves known as the child. */
  202.  
  203.                                     GlobalBase -> Child = HandlerProcess;
  204.  
  205.                                         /* Wake up the father process. */
  206.  
  207.                                     Signal(GlobalBase -> Father,SIG_HANDSHAKE);
  208.  
  209.                                         /* Clear the father id. */
  210.  
  211.                                     GlobalBase -> Father = NULL;
  212.  
  213.                                         /* Disable multitasking and interrupt processing. */
  214.  
  215.                                     Forbid();
  216.                                     Disable();
  217.  
  218.                                         /* Install all the patches. */
  219.  
  220.                                     for(i = 0 ; i < NUM_PATCHES ; i++)
  221.                                     {
  222.                                         WedgeTable[i] . Command    = JMP_ABS;
  223.                                         WedgeTable[i] . Address    = PatchTable[i] . NewRoutine;
  224.  
  225.                                         *PatchTable[i] . Destination = (ULONG)SetFunction(DOSBase,PatchTable[i] . Offset,(APTR)&WedgeTable[i]);
  226.                                     }
  227.  
  228.                                         /* Flush the caches. */
  229.  
  230.                                     CacheClearU();
  231.  
  232.                                         /* Reenable interrupt processing. */
  233.  
  234.                                     Enable();
  235.  
  236.                                         /* We're up and running now. */
  237.  
  238.                                     GlobalBase -> Running = TRUE;
  239.  
  240.                                     do
  241.                                     {
  242.                                             /* Wait for termination signal. */
  243.  
  244.                                         SignalSet = Wait(SIG_KILL | SIG_SHUTDOWN);
  245.  
  246.                                             /* Are we to remove ourselves? */
  247.  
  248.                                         if(SignalSet & SIG_KILL)
  249.                                         {
  250.                                             if(GlobalBase -> Father)
  251.                                                 Terminated = TRUE;
  252.                                         }
  253.  
  254.                                             /* Are we to perform system shutdown? */
  255.  
  256.                                         if(SignalSet & SIG_SHUTDOWN)
  257.                                         {
  258.                                                 /* Are we to close down? */
  259.  
  260.                                             if(!GlobalBase -> Closing)
  261.                                             {
  262.                                                 struct FileInfo        *Node,
  263.                                                             *Next;
  264.                                                 struct ShutdownInfo    *Info,
  265.                                                             *NextInfo;
  266.  
  267.                                                 BYTE             DidFlush = FALSE;
  268.                                                 ULONG             Mode;
  269.  
  270.                                                     /* Get the file info access lock. */
  271.  
  272.                                                 ObtainSemaphore(&GlobalBase -> AccessLock);
  273.  
  274.                                                     /* Block all relevant dos.library functions. */
  275.  
  276.                                                 ObtainSemaphore(&GlobalBase -> BlockLock);
  277.  
  278.                                                     /* The system is going down. */
  279.  
  280.                                                 GlobalBase -> Shutdown = TRUE;
  281.  
  282.                                                     /* Process the file info list. */
  283.  
  284.                                                 Node = (struct FileInfo *)GlobalBase -> AccessList . mlh_Head;
  285.  
  286.                                                 while(Next = (struct FileInfo *)Node -> Node . mln_Succ)
  287.                                                 {
  288.                                                         /* Did the corresponding file get
  289.                                                          * any write accesses? If so,
  290.                                                          * flush the data.
  291.                                                          */
  292.  
  293.                                                     if(Node -> Accesses && Node -> Handle)
  294.                                                     {
  295.                                                             /* Flush the data. */
  296.  
  297.                                                         if(Flush(Node -> Handle))
  298.                                                         {
  299.                                                                 /* Is this the first file
  300.                                                                  * we have to flush? If so,
  301.                                                                  * open the notification
  302.                                                                  * window.
  303.                                                                  */
  304.  
  305.                                                             if(!DidFlush)
  306.                                                             {
  307.                                                                 OpenAll(MODE_RESET);
  308.  
  309.                                                                 DidFlush = TRUE;
  310.                                                             }
  311.                                                         }
  312.                                                     }
  313.  
  314.                                                     Node = Next;
  315.                                                 }
  316.  
  317.                                                     /* Process the callbacks. */
  318.  
  319.                                                 Info = (struct ShutdownInfo *)GlobalBase -> ShutdownList . mlh_Head;
  320.  
  321.                                                 while(NextInfo = (struct ShutdownInfo *)Info -> sdi_Node . mln_Succ)
  322.                                                 {
  323.                                                         /* Call the hook. */
  324.  
  325.                                                     Mode = SD_EXIT;
  326.  
  327.                                                     CallHook(Info -> sdi_Hook,&Mode,SDF_RESET);
  328.  
  329.                                                     Info = NextInfo;
  330.                                                 }
  331.  
  332.                                                     /* Wait for the system to settle. */
  333.  
  334.                                                 if(DidFlush)
  335.                                                     TimeDelay(UNIT_VBLANK,2,0);
  336.  
  337.                                                     /* Carry on with the keyboard reset... */
  338.  
  339.                                                 KeyboardRequest -> io_Command    = KBD_RESETHANDLERDONE;
  340.                                                 KeyboardRequest -> io_Data    = (APTR)KeyboardReset;
  341.  
  342.                                                 DoIO(KeyboardRequest);
  343.                                             }
  344.  
  345.                                                 /* Drop down dead. */
  346.  
  347.                                             Wait(NULL);
  348.                                         }
  349.                                     }
  350.                                     while(!Terminated);
  351.  
  352.                                         /* We're no longer running. */
  353.  
  354.                                     GlobalBase -> Running = FALSE;
  355.  
  356.                                         /* Wait for the system to settle. */
  357.  
  358.                                     TimeDelay(UNIT_VBLANK,2,0);
  359.  
  360.                                         /* Clear the notification signal. */
  361.  
  362.                                     SetSignal(0,SIG_NOTICE);
  363.  
  364.                                         /* Gain access to the user count semaphore. */
  365.  
  366.                                     ObtainSemaphore(&UseCountSemaphore);
  367.  
  368.                                         /* Wait until no program uses our patched
  369.                                          * routines any longer.
  370.                                          */
  371.  
  372.                                     while(UseCount)
  373.                                     {
  374.                                         ReleaseSemaphore(&UseCountSemaphore);
  375.  
  376.                                         Wait(SIG_NOTICE);
  377.  
  378.                                         ObtainSemaphore(&UseCountSemaphore);
  379.                                     }
  380.  
  381.                                         /* Release the lock. */
  382.  
  383.                                     ReleaseSemaphore(&UseCountSemaphore);
  384.  
  385.                                         /* Turn off interrupt processing. */
  386.  
  387.                                     Disable();
  388.  
  389.                                         /* Redirect the wedges to point to the
  390.                                          * original routines.
  391.                                          */
  392.  
  393.                                     for(i = 0 ; i < NUM_PATCHES ; i++)
  394.                                         WedgeTable[i] . Address    = (APTR)*PatchTable[i] . Destination;
  395.  
  396.                                         /* Flush the caches. */
  397.  
  398.                                     CacheClearU();
  399.  
  400.                                         /* Reenable interrupt processing. */
  401.  
  402.                                     Enable();
  403.  
  404.                                         /* Process the file info list. */
  405.  
  406.                                     FileInfo = (struct FileInfo *)GlobalBase -> AccessList . mlh_Head;
  407.  
  408.                                     while(FileInfo -> Node . mln_Succ)
  409.                                     {
  410.                                         NextInfo = (struct FileInfo *)FileInfo -> Node . mln_Succ;
  411.  
  412.                                         Remove((struct Node *)FileInfo);
  413.  
  414.                                         FreeVec(FileInfo);
  415.  
  416.                                         FileInfo = NextInfo;
  417.                                     }
  418.  
  419.                                         /* Reset the device wedges. */
  420.  
  421.                                     DeleteWedges();
  422.  
  423.                                         /* Close the locale catalog tables. */
  424.  
  425.                                     LocaleClose();
  426.                                 }
  427.                                 else
  428.                                     FreeMem(WedgeTable,sizeof(struct Wedge) * NUM_PATCHES);
  429.                             }
  430.                             else
  431.                                 GlobalBase -> ErrorCode = ERROR_NOTABLE,
  432.  
  433.                                 /* Remove the keyboard reset handler. */
  434.  
  435.                             KeyboardRequest -> io_Command    = KBD_REMRESETHANDLER;
  436.                             KeyboardRequest -> io_Data    = (APTR)KeyboardReset;
  437.  
  438.                             DoIO(KeyboardRequest);
  439.                         }
  440.                         else
  441.                             GlobalBase -> ErrorCode = ERROR_NORESET;
  442.                     }
  443.                     else
  444.                         GlobalBase -> ErrorCode = ERROR_WEDGESETUP;
  445.  
  446.                         /* Free the keyboard reset handler. */
  447.  
  448.                     FreeVec(KeyboardReset);
  449.                 }
  450.                 else
  451.                     GlobalBase -> ErrorCode = ERROR_NOKEYRESET;
  452.  
  453.                     /* Close the keyboard.device. */
  454.  
  455.                 CloseDevice(KeyboardRequest);
  456.             }
  457.             else
  458.                 GlobalBase -> ErrorCode = ERROR_NOKEYDEVICE;
  459.  
  460.                 /* Delete the keyboard request. */
  461.  
  462.             DeleteIORequest(KeyboardRequest);
  463.         }
  464.         else
  465.             GlobalBase -> ErrorCode = ERROR_NOKEYREQUEST;
  466.  
  467.             /* Delete the keyboard reply port. */
  468.  
  469.         DeleteMsgPort(KeyboardPort);
  470.     }
  471.     else
  472.         GlobalBase -> ErrorCode = ERROR_NOKEYPORT;
  473.  
  474.     Forbid();
  475.  
  476.         /* We are no longer running. */
  477.  
  478.     GlobalBase -> Running    = FALSE;
  479.  
  480.     GlobalBase -> Child    = NULL;
  481.  
  482.         /* Ring back and fall through. */
  483.  
  484.     Signal(GlobalBase -> Father,SIG_HANDSHAKE);
  485. }
  486.  
  487.     /* ResetCode():
  488.      *
  489.      *    The keyboard reset handler code actually calls
  490.      * this routine.
  491.      */
  492.  
  493. STATIC VOID __saveds
  494. ResetCode()
  495. {
  496.     Signal(HandlerProcess,SIG_SHUTDOWN);
  497. }
  498.  
  499.     /* RegisterAccess(BPTR Handle):
  500.      *
  501.      *    Register a write access to a file handle.
  502.      */
  503.  
  504. STATIC VOID __regargs
  505. RegisterAccess(BPTR Handle)
  506. {
  507.     struct FileInfo    *FileInfo;
  508.     BYTE         GotIt = FALSE;
  509.  
  510.         /* Gain access to the file info list. */
  511.  
  512.     ObtainSemaphore(&GlobalBase -> AccessLock);
  513.  
  514.         /* Scan the list for a fitting file handle. */
  515.  
  516.     FileInfo = (struct FileInfo *)GlobalBase -> AccessList . mlh_Head;
  517.  
  518.     while(FileInfo -> Node . mln_Succ)
  519.     {
  520.             /* Is this the one we want? */
  521.  
  522.         if(FileInfo -> Handle == Handle)
  523.         {
  524.                 /* Remember the last accessor. */
  525.  
  526.             FileInfo -> LastAccess = (struct Process *)SysBase -> ThisTask;
  527.  
  528.                 /* Add up the number of write accesses. */
  529.  
  530.             FileInfo -> Accesses++;
  531.  
  532.                 /* We got a file handle. */
  533.  
  534.             GotIt = TRUE;
  535.  
  536.             break;
  537.         }
  538.         else
  539.             FileInfo = (struct FileInfo *)FileInfo -> Node . mln_Succ;
  540.     }
  541.  
  542.         /* Release the file info access lock. */
  543.  
  544.     ReleaseSemaphore(&GlobalBase -> AccessLock);
  545.  
  546.         /* Block if the system is going down. */
  547.  
  548.     if(GotIt && GlobalBase -> Shutdown)
  549.     {
  550.         ObtainSemaphoreShared(&GlobalBase -> BlockLock);
  551.  
  552.         ReleaseSemaphore(&GlobalBase -> BlockLock);
  553.     }
  554. }
  555.  
  556.     /* MyOpen(register __d1 STRPTR Name,register __d2 LONG Mode):
  557.      *
  558.      *    Modified Open() routine.
  559.      */
  560.  
  561. BPTR __asm
  562. MyOpen(register __d1 STRPTR Name,register __d2 LONG Mode)
  563. {
  564.         /* Is the shutdown process running? */
  565.  
  566.     if(GlobalBase -> Running)
  567.     {
  568.             /* Is it a real disk device the name refers to? */
  569.  
  570.         if(strcmp(Name,"*") && Stricmp(Name,"CONSOLE:"))
  571.         {
  572.             UBYTE    Buffer[50];
  573.             BYTE    GotColon    = FALSE,
  574.                 IsHandler    = FALSE;
  575.             WORD    Count;
  576.             BPTR    File;
  577.  
  578.                 /* Is the system going down? */
  579.  
  580.             if(GlobalBase -> Shutdown)
  581.             {
  582.                 ObtainSemaphoreShared(&GlobalBase -> BlockLock);
  583.  
  584.                 ReleaseSemaphore(&GlobalBase -> BlockLock);
  585.             }
  586.  
  587.                 /* Increment the routine user count. */
  588.  
  589.             ObtainSemaphore(&UseCountSemaphore);
  590.  
  591.             UseCount++;
  592.  
  593.             ReleaseSemaphore(&UseCountSemaphore);
  594.  
  595.                 /* Look for the device name part of the file name. */
  596.  
  597.             Count = 0;
  598.  
  599.             while(Name[Count] && Count < 49)
  600.             {
  601.                 if(Name[Count] != ':')
  602.                 {
  603.                     Buffer[Count] = Name[Count];
  604.  
  605.                     Count++;
  606.                 }
  607.                 else
  608.                 {
  609.                     Buffer[Count] = 0;
  610.  
  611.                     GotColon = TRUE;
  612.  
  613.                     break;
  614.                 }
  615.             }
  616.  
  617.                 /* Did we get a device name? */
  618.  
  619.             if(GotColon && Buffer[0])
  620.             {
  621.                 struct DosList *DosEntry;
  622.  
  623.                     /* Scan the doslist for device entries. */
  624.  
  625.                 if(DosEntry = LockDosList(LDF_DEVICES | LDF_READ))
  626.                 {
  627.                         /* Find a matching entry. */
  628.  
  629.                     if(DosEntry = FindDosEntry(DosEntry,Buffer,LDF_DEVICES))
  630.                     {
  631.                             /* Is it really a device? */
  632.  
  633.                         if(DosEntry -> dol_Type == DLT_DEVICE)
  634.                         {
  635.                                 /* If it has a valid filesystem startup
  636.                                  * entry, it's probably a `real' device.
  637.                                  * If not, it could be filesystem (handler)
  638.                                  * only.
  639.                                  */
  640.  
  641.                             if(!TypeOfMem(BADDR(DosEntry -> dol_misc . dol_handler . dol_Startup)))
  642.                                 IsHandler = TRUE;
  643.                             else
  644.                             {
  645.                                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosEntry -> dol_misc . dol_handler . dol_Startup);
  646.  
  647.                                     /* Are the device and environment vectors
  648.                                      * correct?
  649.                                      */
  650.  
  651.                                 if(TypeOfMem(BADDR(FSSM -> fssm_Device)) && TypeOfMem(BADDR(FSSM -> fssm_Environ)))
  652.                                 {
  653.                                     struct IOStdReq __aligned TestRequest;
  654.  
  655.                                     memset(&TestRequest,0,sizeof(TestRequest));
  656.  
  657.                                         /* Try to open the corresponding
  658.                                          * device driver.
  659.                                          */
  660.  
  661.                                     if(OpenDevice(&((UBYTE *)BADDR(FSSM -> fssm_Device))[1],FSSM -> fssm_Unit,&TestRequest,FSSM -> fssm_Flags))
  662.                                         IsHandler = TRUE;
  663.                                     else
  664.                                         CloseDevice(&TestRequest);
  665.                                 }
  666.                             }
  667.                         }
  668.                     }
  669.  
  670.                         /* Release the lock on the doslist. */
  671.  
  672.                     UnLockDosList(LDF_DEVICES | LDF_READ);
  673.                 }
  674.             }
  675.  
  676.                 /* If the name refers to a device we will
  677.                  * probably have to install a wedge in the
  678.                  * device BeginIO() vector.
  679.                  */
  680.  
  681.             if(!IsHandler)
  682.             {
  683.                     /* Open the file. */
  684.  
  685.                 if(File = OldOpen(Name,Mode,DOSBase))
  686.                 {
  687.                     struct FileHandle *FileHandle = (struct FileHandle *)BADDR(File);
  688.  
  689.                         /* Is there any filesystem process to
  690.                          * handle the file IO?
  691.                          */
  692.  
  693.                     if(FileHandle -> fh_Type)
  694.                     {
  695.                         struct DosList        *DosEntry;
  696.                         struct DeviceNode    *DeviceNode = NULL;
  697.                         BYTE             Ignore = FALSE;
  698.  
  699.                             /* Scan the doslist for device entries... */
  700.  
  701.                         if(DosEntry = LockDosList(LDF_DEVICES | LDF_READ))
  702.                         {
  703.                                 /* Scan until the list is exhausted. */
  704.  
  705.                             while(DosEntry = NextDosEntry(DosEntry,LDF_DEVICES | LDF_READ))
  706.                             {
  707.                                     /* If the filesystem process addresses match then
  708.                                      * we have finally found the device (not the volume!)
  709.                                      * the file is located on.
  710.                                      */
  711.  
  712.                                 if(DosEntry -> dol_Task == FileHandle -> fh_Type)
  713.                                 {
  714.                                         /* Does the device have a correct filesystem
  715.                                          * startup entry?
  716.                                          */
  717.  
  718.                                     if(TypeOfMem(BADDR(DosEntry -> dol_misc . dol_handler . dol_Startup)))
  719.                                     {
  720.                                         struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosEntry -> dol_misc . dol_handler . dol_Startup);
  721.  
  722.                                             /* Are the device and the environment vector correct? */
  723.  
  724.                                         if(TypeOfMem(BADDR(FSSM -> fssm_Device)) && TypeOfMem(BADDR(FSSM -> fssm_Environ)))
  725.                                         {
  726.                                             struct IOStdReq __aligned TestRequest;
  727.  
  728.                                             memset(&TestRequest,0,sizeof(TestRequest));
  729.  
  730.                                                 /* Try to open the corresponding device. */
  731.  
  732.                                             if(!OpenDevice(&((UBYTE *)BADDR(FSSM -> fssm_Device))[1],FSSM -> fssm_Unit,&TestRequest,FSSM -> fssm_Flags))
  733.                                             {
  734.                                                 STRPTR    Name;
  735.                                                 WORD    i;
  736.  
  737.                                                     /* Install the BeginIO() vector wedge. */
  738.  
  739.                                                 NewWedge(&((UBYTE *)BADDR(FSSM -> fssm_Device))[1]);
  740.  
  741.                                                     /* Close the device again. */
  742.  
  743.                                                 CloseDevice(&TestRequest);
  744.  
  745.                                                     /* Check the device name to see if we
  746.                                                      * are to ignore the device driver
  747.                                                      * activity.
  748.                                                      */
  749.  
  750.                                                 DeviceNode = (struct DeviceNode *)DosEntry;
  751.  
  752.                                                 Name = FilePart(&((UBYTE *)BADDR(FSSM -> fssm_Device))[1]);
  753.  
  754.                                                 for(i = 0 ; Ignored[i] ; i++)
  755.                                                 {
  756.                                                     if(!Stricmp(Name,Ignored[i]))
  757.                                                     {
  758.                                                         Ignore = TRUE;
  759.  
  760.                                                         break;
  761.                                                     }
  762.                                                 }
  763.  
  764.                                                 break;
  765.                                             }
  766.                                         }
  767.                                     }
  768.                                 }
  769.                             }
  770.  
  771.                                 /* Release the lock on the list. */
  772.  
  773.                             UnLockDosList(LDF_DEVICES | LDF_READ);
  774.                         }
  775.  
  776.                             /* Did we find a matching device node? */
  777.  
  778.                         if(DeviceNode)
  779.                         {
  780.                             struct FileInfo *FileInfo;
  781.  
  782.                                 /* Create a new fileinfo handle. */
  783.  
  784.                             if(FileInfo = (struct FileInfo *)AllocVec(sizeof(struct FileInfo) + strlen(Name),MEMF_ANY|MEMF_CLEAR))
  785.                             {
  786.                                     /* Fill in the common data. */
  787.  
  788.                                 FileInfo -> Handle    = File;
  789.                                 FileInfo -> LastAccess    = (struct Process *)SysBase -> ThisTask;
  790.                                 FileInfo -> Ignore    = Ignore;
  791.                                 FileInfo -> DeviceNode    = DeviceNode;
  792.  
  793.                                 strcpy(FileInfo -> Name,Name);
  794.  
  795.                                     /* Add it to the list. */
  796.  
  797.                                 ObtainSemaphore(&GlobalBase -> AccessLock);
  798.  
  799.                                 AddTail((struct List *)&GlobalBase -> AccessList,(struct Node *)FileInfo);
  800.  
  801.                                     /* Increase the number of files open. */
  802.  
  803.                                 GlobalBase -> OpenCount++;
  804.  
  805.                                 ReleaseSemaphore(&GlobalBase -> AccessLock);
  806.                             }
  807.                         }
  808.                     }
  809.                 }
  810.             }
  811.             else
  812.                 File = OldOpen(Name,Mode,DOSBase);
  813.  
  814.                 /* Decrement the patch user count. */
  815.  
  816.             ObtainSemaphore(&UseCountSemaphore);
  817.  
  818.             UseCount--;
  819.  
  820.             ReleaseSemaphore(&UseCountSemaphore);
  821.  
  822.                 /* Notify the shutdown process. */
  823.  
  824.             Signal(HandlerProcess,SIG_NOTICE);
  825.  
  826.                 /* Return the result. */
  827.  
  828.             return(File);
  829.         }
  830.         else
  831.             return(OldOpen(Name,Mode,DOSBase));
  832.     }
  833.     else
  834.         return(OldOpen(Name,Mode,DOSBase));
  835. }
  836.  
  837.     /* MyClose(register __d1 BPTR Handle):
  838.      *
  839.      *    Modified Close() routine.
  840.      */
  841.  
  842. LONG __asm
  843. MyClose(register __d1 BPTR Handle)
  844. {
  845.         /* Is the shutdown process running? */
  846.  
  847.     if(GlobalBase -> Running)
  848.     {
  849.         struct FileInfo *FileInfo;
  850.         LONG         Result;
  851.  
  852.                 /* Increment the routine user count. */
  853.  
  854.         ObtainSemaphore(&UseCountSemaphore);
  855.  
  856.         UseCount++;
  857.  
  858.         ReleaseSemaphore(&UseCountSemaphore);
  859.  
  860.             /* Gain access to the fileinfo list. */
  861.  
  862.         ObtainSemaphore(&GlobalBase -> AccessLock);
  863.  
  864.         FileInfo = (struct FileInfo *)GlobalBase -> AccessList . mlh_Head;
  865.  
  866.             /* Look for a fileinfo structure to match
  867.              * the current filehandle pointer.
  868.              */
  869.  
  870.         while(FileInfo -> Node . mln_Succ)
  871.         {
  872.             if(FileInfo -> Handle == Handle)
  873.             {
  874.                 GlobalBase -> OpenCount--;
  875.  
  876.                 Remove((struct Node *)FileInfo);
  877.  
  878.                 FreeVec(FileInfo);
  879.  
  880.                 break;
  881.             }
  882.  
  883.             FileInfo = (struct FileInfo *)FileInfo -> Node . mln_Succ;
  884.         }
  885.  
  886.         ReleaseSemaphore(&GlobalBase -> AccessLock);
  887.  
  888.             /* Close the file handle. */
  889.  
  890.         Result = OldClose(Handle,DOSBase);
  891.  
  892.             /* Decrement routine user count. */
  893.  
  894.         ObtainSemaphore(&UseCountSemaphore);
  895.  
  896.         UseCount--;
  897.  
  898.         ReleaseSemaphore(&UseCountSemaphore);
  899.  
  900.             /* Notify the shutdown process. */
  901.  
  902.         Signal(HandlerProcess,SIG_NOTICE);
  903.  
  904.             /* Return the result. */
  905.  
  906.         return(Result);
  907.     }
  908.     else
  909.         return(OldClose(Handle,DOSBase));
  910. }
  911.  
  912.     /* MyWrite():
  913.      *
  914.      *    Modified Write() routine.
  915.      */
  916.  
  917. LONG __asm
  918. MyWrite(register __d1 BPTR Handle,register __d2 APTR Buffer,register __d3 LONG Length)
  919. {
  920.         /* Is the shutdown process still running and are any bytes to write? */
  921.  
  922.     if(Length && GlobalBase -> Running)
  923.     {
  924.         LONG Result;
  925.  
  926.             /* Increment the routine user count. */
  927.  
  928.         ObtainSemaphore(&UseCountSemaphore);
  929.  
  930.         UseCount++;
  931.  
  932.         ReleaseSemaphore(&UseCountSemaphore);
  933.  
  934.             /* Register the write access. */
  935.  
  936.         RegisterAccess(Handle);
  937.  
  938.             /* Write the data. */
  939.  
  940.         Result = OldWrite(Handle,Buffer,Length,DOSBase);
  941.  
  942.             /* Decrement the routine user count. */
  943.  
  944.         ObtainSemaphore(&UseCountSemaphore);
  945.  
  946.         UseCount--;
  947.  
  948.         ReleaseSemaphore(&UseCountSemaphore);
  949.  
  950.             /* Notify the shutdown process. */
  951.  
  952.         Signal(HandlerProcess,SIG_NOTICE);
  953.  
  954.             /* Return the result. */
  955.  
  956.         return(Result);
  957.     }
  958.     else
  959.         return(OldWrite(Handle,Buffer,Length,DOSBase));
  960. }
  961.  
  962.     /* MyFPutC():
  963.      *
  964.      *    Modified FPutC() routine.
  965.      */
  966.  
  967. LONG __asm
  968. MyFPutC(register __d1 BPTR Handle,register __d2 UBYTE Char)
  969. {
  970.         /* Is the shutdown process still running? */
  971.  
  972.     if(GlobalBase -> Running)
  973.     {
  974.         LONG Result;
  975.  
  976.             /* Increment routine user count. */
  977.  
  978.         ObtainSemaphore(&UseCountSemaphore);
  979.  
  980.         UseCount++;
  981.  
  982.         ReleaseSemaphore(&UseCountSemaphore);
  983.  
  984.             /* Register the write access. */
  985.  
  986.         RegisterAccess(Handle);
  987.  
  988.             /* Output the character. */
  989.  
  990.         Result = OldFPutC(Handle,Char,DOSBase);
  991.  
  992.             /* Decrement the routine user count. */
  993.  
  994.         ObtainSemaphore(&UseCountSemaphore);
  995.  
  996.         UseCount--;
  997.  
  998.         ReleaseSemaphore(&UseCountSemaphore);
  999.  
  1000.             /* Notify the shutdown process. */
  1001.  
  1002.         Signal(HandlerProcess,SIG_NOTICE);
  1003.  
  1004.             /* Return the result. */
  1005.  
  1006.         return(Result);
  1007.     }
  1008.     else
  1009.         return(OldFPutC(Handle,Char,DOSBase));
  1010. }
  1011.  
  1012.     /* MyFPuts(register __d1 BPTR Handle,register __d2 STRPTR String):
  1013.      *
  1014.      *    Modified FPuts() routine.
  1015.      */
  1016.  
  1017. LONG __asm
  1018. MyFPuts(register __d1 BPTR Handle,register __d2 STRPTR String)
  1019. {
  1020.         /* Is the shutdown process still running? */
  1021.  
  1022.     if(GlobalBase -> Running)
  1023.     {
  1024.         LONG Result;
  1025.  
  1026.             /* Increment routine user count. */
  1027.  
  1028.         ObtainSemaphore(&UseCountSemaphore);
  1029.  
  1030.         UseCount++;
  1031.  
  1032.         ReleaseSemaphore(&UseCountSemaphore);
  1033.  
  1034.             /* Register the write access. */
  1035.  
  1036.         RegisterAccess(Handle);
  1037.  
  1038.             /* Output the string. */
  1039.  
  1040.         Result = OldFPuts(Handle,String,DOSBase);
  1041.  
  1042.             /* Decrement the routine user count. */
  1043.  
  1044.         ObtainSemaphore(&UseCountSemaphore);
  1045.  
  1046.         UseCount--;
  1047.  
  1048.         ReleaseSemaphore(&UseCountSemaphore);
  1049.  
  1050.             /* Notify the shutdown process. */
  1051.  
  1052.         Signal(HandlerProcess,SIG_NOTICE);
  1053.  
  1054.             /* Return the result. */
  1055.  
  1056.         return(Result);
  1057.     }
  1058.     else
  1059.         return(OldFPuts(Handle,String,DOSBase));
  1060. }
  1061.  
  1062.     /* MyFWrite():
  1063.      *
  1064.      *    Modified FWrite() routine.
  1065.      */
  1066.  
  1067. LONG __asm
  1068. MyFWrite(register __d1 BPTR Handle,register __d2 STRPTR Buffer,register __d3 ULONG BlockLen,register __d4 ULONG Blocks)
  1069. {
  1070.         /* Is the shutdown process still running? */
  1071.  
  1072.     if(GlobalBase -> Running)
  1073.     {
  1074.         LONG Result;
  1075.  
  1076.             /* Increment routine user count. */
  1077.  
  1078.         ObtainSemaphore(&UseCountSemaphore);
  1079.  
  1080.         UseCount++;
  1081.  
  1082.         ReleaseSemaphore(&UseCountSemaphore);
  1083.  
  1084.             /* Register the write access. */
  1085.  
  1086.         RegisterAccess(Handle);
  1087.  
  1088.             /* Write the data. */
  1089.  
  1090.         Result = OldFWrite(Handle,Buffer,BlockLen,Blocks,DOSBase);
  1091.  
  1092.             /* Decrement the routine user count. */
  1093.  
  1094.         ObtainSemaphore(&UseCountSemaphore);
  1095.  
  1096.         UseCount--;
  1097.  
  1098.         ReleaseSemaphore(&UseCountSemaphore);
  1099.  
  1100.             /* Notify the shutdown process. */
  1101.  
  1102.         Signal(HandlerProcess,SIG_NOTICE);
  1103.  
  1104.             /* Return the result. */
  1105.  
  1106.         return(Result);
  1107.     }
  1108.     else
  1109.         return(OldFWrite(Handle,Buffer,BlockLen,Blocks,DOSBase));
  1110. }
  1111.  
  1112.     /* MyVFPrintf():
  1113.      *
  1114.      *    Modified VFPrintf() routine.
  1115.      */
  1116.  
  1117. LONG __asm
  1118. MyVFPrintf(register __d1 BPTR Handle,register __d2 STRPTR Format,register __d3 LONG *Args)
  1119. {
  1120.         /* Is the shutdown process still running? */
  1121.  
  1122.     if(GlobalBase -> Running)
  1123.     {
  1124.         LONG Result;
  1125.  
  1126.             /* Increment routine user count. */
  1127.  
  1128.         ObtainSemaphore(&UseCountSemaphore);
  1129.  
  1130.         UseCount++;
  1131.  
  1132.         ReleaseSemaphore(&UseCountSemaphore);
  1133.  
  1134.             /* Register the write access. */
  1135.  
  1136.         RegisterAccess(Handle);
  1137.  
  1138.             /* Output the text. */
  1139.  
  1140.         Result = OldVFPrintf(Handle,Format,Args,DOSBase);
  1141.  
  1142.             /* Decrement the routine user count. */
  1143.  
  1144.         ObtainSemaphore(&UseCountSemaphore);
  1145.  
  1146.         UseCount--;
  1147.  
  1148.         ReleaseSemaphore(&UseCountSemaphore);
  1149.  
  1150.             /* Notify the shutdown process. */
  1151.  
  1152.         Signal(HandlerProcess,SIG_NOTICE);
  1153.  
  1154.             /* Return the result. */
  1155.  
  1156.         return(Result);
  1157.     }
  1158.     else
  1159.         return(OldVFPrintf(Handle,Format,Args,DOSBase));
  1160. }
  1161.  
  1162.     /* MyVFWritef():
  1163.      *
  1164.      *    Modified VFWritef() routine.
  1165.      */
  1166.  
  1167. LONG __asm
  1168. MyVFWritef(register __d1 BPTR Handle,register __d2 STRPTR Format,register __d3 LONG *Args)
  1169. {
  1170.         /* Is the shutdown process still running? */
  1171.  
  1172.     if(GlobalBase -> Running)
  1173.     {
  1174.         LONG Result;
  1175.  
  1176.             /* Increment routine user count. */
  1177.  
  1178.         ObtainSemaphore(&UseCountSemaphore);
  1179.  
  1180.         UseCount++;
  1181.  
  1182.         ReleaseSemaphore(&UseCountSemaphore);
  1183.  
  1184.             /* Register the write access. */
  1185.  
  1186.         RegisterAccess(Handle);
  1187.  
  1188.             /* Write the data. */
  1189.  
  1190.         Result = OldVFWritef(Handle,Format,Args,DOSBase);
  1191.  
  1192.             /* Decrement the routine user count. */
  1193.  
  1194.         ObtainSemaphore(&UseCountSemaphore);
  1195.  
  1196.         UseCount--;
  1197.  
  1198.         ReleaseSemaphore(&UseCountSemaphore);
  1199.  
  1200.             /* Notify the shutdown process. */
  1201.  
  1202.         Signal(HandlerProcess,SIG_NOTICE);
  1203.  
  1204.             /* Return the result. */
  1205.  
  1206.         return(Result);
  1207.     }
  1208.     else
  1209.         return(OldVFWritef(Handle,Format,Args,DOSBase));
  1210. }
  1211.  
  1212.     /* MyPutStr(register __d1 STRPTR Buffer):
  1213.      *
  1214.      *    Modified PutStr() routine.
  1215.      */
  1216.  
  1217. LONG __asm
  1218. MyPutStr(register __d1 STRPTR Buffer)
  1219. {
  1220.         /* Is the shutdown process still running? */
  1221.  
  1222.     if(GlobalBase -> Running)
  1223.     {
  1224.         struct Process    *ThisProcess = (struct Process *)SysBase -> ThisTask;
  1225.         LONG         Result;
  1226.  
  1227.             /* Increment routine user count. */
  1228.  
  1229.         ObtainSemaphore(&UseCountSemaphore);
  1230.  
  1231.         UseCount++;
  1232.  
  1233.         ReleaseSemaphore(&UseCountSemaphore);
  1234.  
  1235.             /* Register the write access. */
  1236.  
  1237.         RegisterAccess(ThisProcess -> pr_COS);
  1238.  
  1239.             /* Output the text. */
  1240.  
  1241.         Result = OldPutStr(Buffer,DOSBase);
  1242.  
  1243.             /* Decrement the routine user count. */
  1244.  
  1245.         ObtainSemaphore(&UseCountSemaphore);
  1246.  
  1247.         UseCount--;
  1248.  
  1249.         ReleaseSemaphore(&UseCountSemaphore);
  1250.  
  1251.             /* Notify the shutdown process. */
  1252.  
  1253.         Signal(HandlerProcess,SIG_NOTICE);
  1254.  
  1255.             /* Return the result. */
  1256.  
  1257.         return(Result);
  1258.     }
  1259.     else
  1260.         return(OldPutStr(Buffer,DOSBase));
  1261. }
  1262.  
  1263.     /* MyWriteChars():
  1264.      *
  1265.      *    Modified WriteChars() routine.
  1266.      */
  1267.  
  1268. LONG __asm
  1269. MyWriteChars(register __d1 STRPTR Buffer,register __d2 ULONG Len)
  1270. {
  1271.         /* Is the shutdown process still running? */
  1272.  
  1273.     if(GlobalBase -> Running)
  1274.     {
  1275.         struct Process    *ThisProcess = (struct Process *)SysBase -> ThisTask;
  1276.         LONG         Result;
  1277.  
  1278.             /* Increment routine user count. */
  1279.  
  1280.         ObtainSemaphore(&UseCountSemaphore);
  1281.  
  1282.         UseCount++;
  1283.  
  1284.         ReleaseSemaphore(&UseCountSemaphore);
  1285.  
  1286.             /* Register the write access. */
  1287.  
  1288.         RegisterAccess(ThisProcess -> pr_COS);
  1289.  
  1290.             /* Write the characters. */
  1291.  
  1292.         Result = OldWriteChars(Buffer,Len,DOSBase);
  1293.  
  1294.             /* Decrement the routine user count. */
  1295.  
  1296.         ObtainSemaphore(&UseCountSemaphore);
  1297.  
  1298.         UseCount--;
  1299.  
  1300.         ReleaseSemaphore(&UseCountSemaphore);
  1301.  
  1302.             /* Notify the shutdown process. */
  1303.  
  1304.         Signal(HandlerProcess,SIG_NOTICE);
  1305.  
  1306.             /* Return the result. */
  1307.  
  1308.         return(Result);
  1309.     }
  1310.     else
  1311.         return(OldWriteChars(Buffer,Len,DOSBase));
  1312. }
  1313.  
  1314.     /* MyVPrintf():
  1315.      *
  1316.      *    Modified VPrintf() routine.
  1317.      */
  1318.  
  1319. LONG __asm
  1320. MyVPrintf(register __d1 STRPTR Format,register __d2 LONG *Args)
  1321. {
  1322.         /* Is the shutdown process still running? */
  1323.  
  1324.     if(GlobalBase -> Running)
  1325.     {
  1326.         struct Process    *ThisProcess = (struct Process *)SysBase -> ThisTask;
  1327.         LONG         Result;
  1328.  
  1329.             /* Increment routine user count. */
  1330.  
  1331.         ObtainSemaphore(&UseCountSemaphore);
  1332.  
  1333.         UseCount++;
  1334.  
  1335.         ReleaseSemaphore(&UseCountSemaphore);
  1336.  
  1337.             /* Register the write access. */
  1338.  
  1339.         RegisterAccess(ThisProcess -> pr_COS);
  1340.  
  1341.             /* Output the text. */
  1342.  
  1343.         Result = OldVPrintf(Format,Args,DOSBase);
  1344.  
  1345.             /* Decrement the routine user count. */
  1346.  
  1347.         ObtainSemaphore(&UseCountSemaphore);
  1348.  
  1349.         UseCount--;
  1350.  
  1351.         ReleaseSemaphore(&UseCountSemaphore);
  1352.  
  1353.             /* Notify the shutdown process. */
  1354.  
  1355.         Signal(HandlerProcess,SIG_NOTICE);
  1356.  
  1357.             /* Return the result. */
  1358.  
  1359.         return(Result);
  1360.     }
  1361.     else
  1362.         return(OldVPrintf(Format,Args,DOSBase));
  1363. }
  1364.