mac-rom/ProcessMgr/FileSystem.c
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

332 lines
8.7 KiB
C

/*
File: FileSystem.c
Contains: Process Mgr file system replacement routines.
Written by: Erich Ringewald
Copyright: © 1987-1991 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<3> 3/5/91 DFH dnf, #84115: Added support for new forced _Unmount (ignore
result of notification proc).
<0> 6/1/87 ELR New Today.
*/
#include <types.h>
#include <memory.h>
#include <menus.h>
#include <osutils.h>
#include <errors.h>
#include <retrace.h>
#include <segload.h>
#include <files.h>
#include <resources.h>
#include <MFPrivate.h>
#include <Folders.h>
#include "Glue.h"
#include "SysMisc.h"
#include "Lomem.h"
#include "Data.h"
#include "Patches.h"
/************************************************************************************
* Here are some interesting file system routines that we use to elevate the
* status of certain volume and disk operations to the system level. This is
* because there are system entities (such as Finder and its desktop database)
* that are really high-level extensions of HFS. They at least need to be told
* about, and sometime need to help out with, the comings and goings on.
************************************************************************************/
typedef struct VNEntry {
struct vnentry **VNNextRequest;
ProcPtr VNRoutine;
unsigned long VNRefcon;
ProcessSerialNumber VNInstaller;
} VNEntry, *VNPointer, **VNHandle;
/* registry for volume aficionados */
VNHandle VolumeNotificationList;
/* Function prototypes internal to this file */
void NotifyVolumeAction(short, VolumeNotice, OSErr, VNHandle);
void ResetStandardFileVol(short);
/* c_RequestVolumeNotification. Enlist to receive a call whenever significant
* disk or volume actions are occurring.
*/
pascal OSErr
c_RequestVolumeNotification(ProcPtr pRoutine, unsigned long refCon)
{
ProcessSerialNumber installer;
VNHandle hNewElem;
u_long oldA5;
OSErr retVal;
retVal = noErr;
oldA5 = ProcessMgrA5SimpleSetup();
/* identify the client */
(void)GetSystemClientProcess(&installer);
/* install new entry */
if ((hNewElem = (VNHandle) ProcessMgrNewHandle(sizeof(VNEntry))) != nil)
{
VNPointer pNewElem;
pNewElem = *hNewElem;
pNewElem->VNRoutine = pRoutine;
pNewElem->VNRefcon = refCon;
pNewElem->VNInstaller = installer;
pNewElem->VNNextRequest = VolumeNotificationList;
VolumeNotificationList = hNewElem;
}
else
retVal = MEMERROR;
A5SimpleRestore(oldA5);
return(retVal);
}
/* c_DeclineVolumeNotification. Resign from volume/disk notifications. */
pascal OSErr
c_DeclineVolumeNotification(ProcPtr pRoutine, unsigned long refCon)
{
VNHandle hBefore, hCurr, hAfter;
VNPointer pCurr;
ProcessSerialNumber remover;
u_long oldA5;
oldA5 = ProcessMgrA5SimpleSetup();
(void)GetCurrentProcess(&remover);
hBefore = nil;
hCurr = VolumeNotificationList;
while (hCurr != nil)
{
pCurr = *hCurr;
if ((pCurr->VNRoutine == pRoutine) &&
(pCurr->VNRefcon == refCon) &&
((EqualPSN(&pCurr->VNInstaller, &remover))
|| (EqualPSNConst(kSystemProcess, &pCurr->VNInstaller))))
{
hAfter = pCurr->VNNextRequest;
DisposHandle(hCurr);
if (hBefore == nil)
VolumeNotificationList = hAfter;
else
(*hBefore)->VNNextRequest = hAfter;
break;
}
hBefore = hCurr;
hCurr = (*hCurr)->VNNextRequest;
}
A5SimpleRestore(oldA5);
return(noErr);
}
/* VNKill. Un-register the dead process from volume notification. */
void
VNKill(void)
{
ProcessSerialNumberPtr pDeadPSN;
register VNHandle hBefore, hCurr, hAfter;
pDeadPSN = &pCurrentProcess->p_serialNumber;
hBefore = nil;
hCurr = VolumeNotificationList;
while (hCurr != nil)
{
/* Grab the forward link *before* disposing the element */
hAfter = (*hCurr)->VNNextRequest;
/* Match up the element to the calling process */
if (EqualPSN(&((*hCurr)->VNInstaller), pDeadPSN))
{
DisposHandle(hCurr);
assert(MEMERROR == noErr);
if (hBefore == nil)
VolumeNotificationList = hAfter;
else
(*hBefore)->VNNextRequest = hAfter;
}
else
hBefore = hCurr;
/* Forge ahead */
hCurr = hAfter;
}
}
#pragma segment Main
/* ResetStandardFileVol. Reset the StandardFile lomems for each process that has its
* StandardFile pointed at the given volume.
* NOTE: It's this way for now to be efficient. When "putting the Process Mgr in ROM",
* you should probably make it a volume notification routine installed by PACK3. It
* would use an OSDispatch call to set the SFSaveDisk and CurDirStore of a process.
* NOTE: Assumes a5 == PROCESSMGRGLOBALS
*/
void
ResetStandardFileVol(short vRefNum)
{
register PCB *pPCB;
PEntryPtr pProc;
/* Turn vRefNum to volume index because that's what StandardFile uses */
vRefNum = -(vRefNum);
/* Fix up contexts for all processes. Effect will be on next minor switch in. */
pProc = pProcessList;
while (pProc != nil)
{
pPCB = *(pProc->p_pcb);
if (pPCB->sfsavedisk == vRefNum)
{
pPCB->sfsavedisk = 1;
pPCB->curdirstore = fsRtDirID;
}
pProc = pProc->p_NextProcess;
}
/* Make sure effect is immediate for current process */
if (SFSAVEDISK == vRefNum)
{
SFSAVEDISK = 1;
CURDIRSTORE = fsRtDirID;
}
}
/* NotifyVolumeAction. Notify all interested parties of a volume action that
* has just occurred. A non-nil hEnd can be used to stop the traversal early
* (notification proceeds from the first element up to, but not including, the
* one addressed by hEnd).
* NOTE: Assumes the list does not change in the notification routine!!
* NOTE: Assumes a5 == PROCESSMGRGLOBALS
*/
void
NotifyVolumeAction(short theVolume, VolumeNotice theNotice, OSErr theResult, VNHandle hEnd)
{
VNHandle hCurr;
VolumeNoticeBlk vnBlock;
OSErr result;
/* Reset StandardFile lomem when volume successfully unmounted. */
if (theNotice == VNUnmount && theResult == noErr)
ResetStandardFileVol(theVolume);
/* Fill in the parameter block */
vnBlock.VNBNotice = theNotice;
vnBlock.VNBVolume = theVolume;
vnBlock.VNBResult = theResult;
vnBlock.VNBLength = sizeof(VolumeNoticeBlk);
/* Tell everyone */
hEnd = (VNHandle) StripAddress(hEnd);
hCurr = (VNHandle) StripAddress(VolumeNotificationList);
while (hCurr != hEnd)
{
vnBlock.VNBRefCon = (*hCurr)->VNRefcon;
result = CALL_FNC_PTR(VNProcPtr, (*hCurr)->VNRoutine, (&vnBlock));
hCurr = (VNHandle) StripAddress((*hCurr)->VNNextRequest);
}
}
/* NotifyVolumeGoodbye. Notify all interested parties that the given volume is
* about to be ejected or unmounted. If anyone objects, we abort and pass the
* error back to the caller (this action can be overriden by specifying the
* forced parameter as true).
* NOTE: Assumes the list does not change in the notification routine!!
* NOTE: Assumes a5 == PROCESSMGRGLOBALS
*/
OSErr
NotifyVolumeGoodbye(short theVolume, VolumeNotice theNotice, VolumeNotice theAbortNotice, Boolean forced)
{
VNHandle hCurr;
VolumeNoticeBlk vnBlock;
OSErr retval;
/* Fill in the parameter block */
vnBlock.VNBNotice = theNotice;
vnBlock.VNBVolume = theVolume;
vnBlock.VNBResult = noErr;
vnBlock.VNBLength = sizeof(VolumeNoticeBlk);
/* Tell everyone */
hCurr = VolumeNotificationList;
while (hCurr != nil)
{
vnBlock.VNBRefCon = (*hCurr)->VNRefcon;
retval = CALL_FNC_PTR(VNProcPtr, (*hCurr)->VNRoutine, (&vnBlock));
if ((retval != noErr) && (forced == false))
{
NotifyVolumeAction(theVolume, theAbortNotice, retval, hCurr);
return(retval);
}
hCurr = (*hCurr)->VNNextRequest;
}
return(noErr);
}
#pragma segment INIT
/* VNInit. Initialize list volume registration. */
void
VNInit(void)
{
VolumeNotificationList = nil;
}
/************************************************************************************
* Useful utilities related to HFS.
************************************************************************************/
#pragma segment Main
/* DecomposeWD. Simple utility routine to extract the vRefNum and dirID components
* of the specified working directory.
*/
OSErr
DecomposeWD(short srcWD, short *dstVolume, unsigned long *dstDirID)
{
WDPBRec wdInfoRec;
OSErr result;
wdInfoRec.ioNamePtr = nil;
wdInfoRec.ioVRefNum = srcWD;
wdInfoRec.ioWDIndex = 0;
wdInfoRec.ioWDProcID = 0;
wdInfoRec.ioWDVRefNum = 0;
wdInfoRec.ioCompletion = nil;
if ((result = PBGetWDInfo(&wdInfoRec, SyncHFS)) == noErr)
{
*dstVolume = wdInfoRec.ioWDVRefNum;
*dstDirID = wdInfoRec.ioWDDirID;
}
else
{
*dstVolume = 0;
*dstDirID = 0;
}
return(result);
}
/* CheckIfBackingWD. Check whether the given WD is the one into which the current
* application was launched.
*/
pascal Boolean
CheckIfBackingWD(short wdRefNum)
{
PCB **hPCB;
return(((hPCB = pCurrentProcess->p_pcb) != nil) && (wdRefNum == (*hPCB)->p_vrefnum));
}