mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +00:00
4325cdcc78
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.
332 lines
8.7 KiB
C
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));
|
|
}
|