mac-rom/OS/HFS/Extensions/FSSpecCalls.c
Elliot Nunn 0ba83392d4 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-09-20 18:04:16 +08:00

494 lines
14 KiB
C

/*
File: FSSpecCalls.c
Contains: The FSp wrapper calls to the file system
Written by: Dave Feldman
Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<11> 4/4/92 FM #1021881,<DTY>: Add two new calls to turn the ProcessMgr's file
tracking on and off. SuspendFileTracking and ResumeFileTracking.
These wil be internal calls for a while.
<10> 9/13/91 JSM Cleanup header.
<9> 1/13/91 dnf (jdr) Add compatibility code for FSpExchangeFiles.
<8> 12/21/90 JL changed constStrxxParameter to ConstStrxxxParam to match change
in Types.h
<7> 12/14/90 dnf (w/dba) Have FSpDirCreate use SetCatInfo instead of SetFInfo.
Changed FSSpecPtr to use const on all calls except FSMakeFSSpec.
Changed const StringPtr (which doesn't work) to
constStr255Parameter (which does). Get the resource error with
RESERR.
<6> 10/30/90 dnf Set script code byte on create calls. Set ResErr on resource
manager calls. Switch to PBxxxSync calls.
<5> 10/2/90 JAL Changed all occurances of .hfileInfo to .hFileInfo to match Interface change
<4> 8/28/90 dnf Add FSpExchangeFiles
<3> 8/6/90 dnf Rename implementation routines to use two underscores.
<2> 8/6/90 dnf Changed routine headers to match latest in files.h.
<1> 8/6/90 dnf first checked in
*/
#include <Types.h>
#include <Errors.h>
#include <Files.h>
#include <MFPrivate.h> // <11>
#include <Resources.h>
#include <Traps.h>
#include <SysEqu.h>
/* this is needed for Resource Manager glue */
#define RESERR (* (OSErr *) ResErr)
/* Utility Routine */
/* Munge a script manager style script code word into encoding used
for Finder xInfo.
In script manager-land, values 0-64 are defined and
-1 and -2 are special marker values. The Finder xInfo
definition is that 0 implies "unused" and a high bit
set indicates that the byte is in use. The script manager's
-1 and -2 marker values have no meaning on disk, so this
encoding works out.
*/
char ConvertScriptCodeToDiskForm(ScriptCode scriptTag)
{
char diskScriptCode;
if (scriptTag >= 0)
diskScriptCode = scriptTag | 0x80; /* set high bit to mark valid */
else
diskScriptCode = 0; /* garbage, so leave unused */
return(diskScriptCode);
}
/* File Manager routines */
pascal OSErr __FSpOpenDF(const FSSpec* spec, char permission, short *refNum)
{
OSErr error;
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
pb.ioParam.ioPermssn = permission;
pb.ioParam.ioMisc = nil;
error = PBHOpenDFSync(&pb);
*refNum = pb.ioParam.ioRefNum;
return(error);
}
pascal OSErr __FSpOpenRF(const FSSpec* spec, char permission, short *refNum)
{
OSErr error;
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
pb.ioParam.ioPermssn = permission;
pb.ioParam.ioMisc = nil;
error = PBHOpenRFSync(&pb);
*refNum = pb.ioParam.ioRefNum;
return(error);
}
pascal OSErr __FSpCreate(const FSSpec* spec, OSType creator, OSType fileType, ScriptCode scriptTag)
{
OSErr error;
HFileInfo pb;
pb.ioVRefNum = spec -> vRefNum;
pb.ioDirID = spec -> parID;
pb.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioFVersNum = 0;
((HParmBlkPtr) &pb) -> ioParam.ioVersNum = 0;
error = PBHCreateSync((HParmBlkPtr) &pb);
if (error == noErr) {
pb.ioFDirIndex = 0;
error = PBHGetFInfoSync((HParmBlkPtr) &pb);
if (error == noErr) {
pb.ioFlXFndrInfo.fdScript = ConvertScriptCodeToDiskForm(scriptTag);
pb.ioFlFndrInfo.fdCreator = creator;
pb.ioFlFndrInfo.fdType = fileType;
pb.ioDirID = spec -> parID;
error = PBHSetFInfoSync((HParmBlkPtr)&pb);
}
}
return(error);
}
pascal OSErr __FSpDirCreate(const FSSpec* spec, ScriptCode scriptTag, long *createdDirID)
{
OSErr error;
CInfoPBRec cinfo;
cinfo.dirInfo.ioVRefNum = spec -> vRefNum;
cinfo.dirInfo.ioDrDirID = spec -> parID;
cinfo.dirInfo.ioNamePtr = (StringPtr) &(spec -> name);
error = PBDirCreateSync((HParmBlkPtr) &cinfo);
*createdDirID = cinfo.dirInfo.ioDrDirID;
if (error == noErr) {
cinfo.dirInfo.ioFDirIndex = 0;
cinfo.dirInfo.ioDrDirID = spec -> parID;
error = PBGetCatInfoSync(&cinfo);
if (error == noErr) {
cinfo.dirInfo.ioDrFndrInfo.frScript = ConvertScriptCodeToDiskForm(scriptTag);
cinfo.dirInfo.ioDrDirID = spec -> parID;
error = PBSetCatInfoSync(&cinfo);
}
}
return(error);
}
pascal OSErr __FSpDelete(const FSSpec* spec)
{
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
return(PBHDeleteSync(&pb));
}
pascal OSErr __FSpGetFInfo(const FSSpec* spec, FInfo *fndrInfo)
{
OSErr error;
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
pb.fileParam.ioFDirIndex = 0;
error = PBHGetFInfoSync(&pb);
*fndrInfo = pb.fileParam.ioFlFndrInfo;
return(error);
}
pascal OSErr __FSpSetFInfo(const FSSpec* spec, const FInfo *fndrInfo)
{
OSErr error;
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
pb.fileParam.ioFDirIndex = 0;
error = PBHGetFInfoSync(&pb);
if (error == noErr) {
pb.fileParam.ioFlFndrInfo = *fndrInfo;
pb.fileParam.ioDirID = spec -> parID;
error = PBHSetFInfoSync(&pb);
}
return(error);
}
pascal OSErr __FSpSetFLock(const FSSpec* spec)
{
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
return(PBHSetFLockSync(&pb));
}
pascal OSErr __FSpRstFLock(const FSSpec* spec)
{
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
return(PBHRstFLockSync(&pb));
}
pascal OSErr __FSpRename(const FSSpec* spec, ConstStr255Param newName)
{
HParamBlockRec pb;
pb.ioParam.ioVRefNum = spec -> vRefNum;
pb.fileParam.ioDirID = spec -> parID;
pb.ioParam.ioNamePtr = (StringPtr) &(spec -> name);
pb.ioParam.ioVersNum = 0;
pb.ioParam.ioMisc = (Ptr) newName;
return(PBHRenameSync(&pb));
}
pascal OSErr __FSpCatMove(const FSSpec* source, const FSSpec* dest)
{
CMovePBRec pb;
if (source -> vRefNum != dest -> vRefNum)
return(paramErr);
pb.ioNamePtr = (StringPtr) &(source -> name);
pb.ioVRefNum = source -> vRefNum;
pb.ioDirID = source -> parID;
pb.ioNewDirID = dest -> parID;
pb.ioNewName = (StringPtr) &(dest -> name);
return(PBCatMoveSync(&pb));
}
pascal short __FSpOpenResFile(const FSSpec* spec, char permission)
{
return(HOpenResFile(spec -> vRefNum, spec -> parID, &(spec -> name), permission));
}
pascal void __FSpCreateResFile(const FSSpec* spec, OSType creator, OSType fileType, ScriptCode scriptTag)
{
OSErr error;
HFileInfo pb;
HCreateResFile(spec -> vRefNum, spec -> parID, &(spec -> name));
if (RESERR == noErr) {
pb.ioVRefNum = spec -> vRefNum;
pb.ioDirID = spec -> parID;
pb.ioNamePtr = (StringPtr) &(spec -> name);
((HParmBlkPtr) &pb) -> ioParam.ioVersNum = 0;
pb.ioFDirIndex = 0;
error = PBHGetFInfoSync((HParmBlkPtr) &pb);
if (error == noErr) {
pb.ioFlXFndrInfo.fdScript = ConvertScriptCodeToDiskForm(scriptTag);
pb.ioFlFndrInfo.fdCreator = creator;
pb.ioFlFndrInfo.fdType = fileType;
pb.ioDirID = spec -> parID;
error = PBHSetFInfoSync((HParmBlkPtr) &pb);
}
RESERR = error;
}
}
pascal OSErr __FSMakeFSSpec( short vRefNum, long dirID, ConstStr255Param fileName, FSSpec* spec)
{
HParamBlockRec pb;
pb.fileParam.ioNamePtr = fileName;
pb.fileParam.ioVRefNum = vRefNum;
pb.fileParam.ioDirID = dirID;
pb.ioParam.ioMisc = (Ptr) spec;
return(PBMakeFSSpecSync(&pb));
}
// This one isnÕt in the interfaces anywhere, but is in the dispatcher.
// We dreamed it up for use by FSpExchangeFiles, but itÕs a bit late
// to make it into Inside Mac. Feel free to add this call later.
pascal OSErr __FSpGetCatInfo(const FSSpec* spec, CInfoPBPtr cinfo)
{
cinfo -> hFileInfo.ioVRefNum = spec -> vRefNum;
cinfo -> hFileInfo.ioFDirIndex = 0;
cinfo -> hFileInfo.ioNamePtr = (StringPtr) &(spec -> name);
cinfo -> hFileInfo.ioDirID = spec -> parID;
return(PBGetCatInfoSync(cinfo));
}
// These 2 routines were needed by Akiko for opening dictionary files. <11>
// Right now they just call BeginSysMode and EndSysMode. Hopefully in the <11>
// future we will be able to release these calls to developers, but for <11>
// now they are internal only.
// Prevent files opened from being closed when the current process
// quits!
pascal OSErr __SuspendProcessMgrFileTracking(void) // <11>
{
OSErr err;
err = BeginSystemMode();
return err;
}
// Now any files opened will close when the current process
// quitsÉ
pascal OSErr __ResumeProcessMgrFileTracking(void) // <11>
{
OSErr err;
err = EndSystemMode();
return err;
}
OSErr IsFile(const FSSpec* spec)
{
CInfoPBRec cinfo;
OSErr error;
if (error = __FSpGetCatInfo(spec, &cinfo))
return(error);
if (cinfo.hFileInfo.ioFlAttrib & ioDirMask)
return(notAFileErr);
else
return(noErr);
}
OSErr GenerateUniqueName(short volume, long *startSeed, long dir1, long dir2, StringPtr uniqueName)
{
OSErr error = noErr;
long i;
CInfoPBRec cinfo;
cinfo.hFileInfo.ioVRefNum = volume;
cinfo.hFileInfo.ioFDirIndex = 0;
cinfo.hFileInfo.ioNamePtr = uniqueName;
while (error != fnfErr) {
(*startSeed)++;
cinfo.hFileInfo.ioNamePtr[0] = 8;
for (i = 1; i <= 8; i++)
cinfo.hFileInfo.ioNamePtr[i] = "0123456789ABCDEF"[((*startSeed >> ((8-i)*4)) & 0xf)];
cinfo.hFileInfo.ioDirID = dir1;
error = fnfErr;
for (i = 1; i <= 2; i++) {
error = error & PBGetCatInfoSync(&cinfo);
cinfo.hFileInfo.ioDirID = dir2;
if ((error != fnfErr) && (error != noErr))
return(error);
}
}
return(noErr);
}
pascal OSErr __FSpExchangeFiles(const FSSpec* source, const FSSpec* dest)
{
HParamBlockRec pb;
CInfoPBRec catInfoSource, catInfoDest;
OSErr error, error2;
Str31 unique1, unique2; // our strings are never more than 11 characters long
StringPtr unique1Ptr, unique2Ptr, swapola;
GetVolParmsInfoBuffer volInfo;
long theSeed, temp;
if (source -> vRefNum != dest -> vRefNum)
return(paramErr);
pb.fidParam.ioNamePtr = (StringPtr) &(source -> name);
pb.fidParam.ioVRefNum = source -> vRefNum;
pb.fidParam.ioDestNamePtr = (StringPtr) &(dest -> name);
pb.fidParam.ioDestDirID = dest -> parID;
pb.fidParam.ioSrcDirID = source -> parID;
error = PBExchangeFilesSync(&pb);
// note that the compatibility case won't work for files with Btree control blocks.
// Right now only system-like files use btrees
if (error) {
pb.ioParam.ioNamePtr = nil;
pb.ioParam.ioBuffer = (Ptr) &volInfo;
pb.ioParam.ioReqCount = sizeof(volInfo);
error2 = PBHGetVolParmsSync(&pb);
// continue if volume has no fileID support (or no GetVolParms support)
if ((error2 == noErr) && (volInfo.vMAttrib & (1<<bHasFileIDs)))
return(error);
// make sure both files are really files
if ((error = IsFile(source)) || (error = IsFile(dest)))
return(error);
// generate 2 filenames that are unique in both directories
theSeed = 0x64666364; // a fine unlikely filename
unique1Ptr = &unique1;
unique2Ptr = &unique2;
if (error = GenerateUniqueName(source -> vRefNum, &theSeed, source -> parID, dest -> parID, unique1Ptr))
return(error);
if (error = GenerateUniqueName(source -> vRefNum, &theSeed, source -> parID, dest -> parID, unique2Ptr))
return(error);
// get the catalog info for each file
if (error = __FSpGetCatInfo(source, &catInfoSource))
return(error);
if (error = __FSpGetCatInfo(dest, &catInfoDest))
return(error);
// rename source to unique1
pb.fileParam.ioNamePtr = (StringPtr) &(source -> name);
pb.ioParam.ioMisc = (Ptr) unique1Ptr;
if (error = PBHRenameSync(&pb))
return(error);
// rename dest to unique2
pb.ioParam.ioMisc = (Ptr) unique2Ptr;
pb.fileParam.ioNamePtr = (StringPtr) &(dest -> name);
pb.fileParam.ioDirID = dest -> parID;
if (error = PBHRenameSync(&pb))
goto error2;
// move source file to dest directory
pb.copyParam.ioNamePtr = unique1Ptr;
pb.copyParam.ioNewName = nil;
pb.copyParam.ioNewDirID = dest -> parID;
pb.copyParam.ioDirID = source -> parID;
if (error = PBCatMoveSync((CMovePBPtr) &pb))
goto error1;
// move dest file to source directory
pb.copyParam.ioNamePtr = unique2Ptr;
pb.copyParam.ioNewDirID = source -> parID;
pb.copyParam.ioDirID = dest -> parID;
if (error = PBCatMoveSync((CMovePBPtr) &pb)) {
// life is very bad. We'll at least try to move source back
pb.copyParam.ioNamePtr = unique1Ptr;
pb.copyParam.ioNewName = nil;
pb.copyParam.ioNewDirID = source -> parID;
pb.copyParam.ioDirID = dest -> parID;
PBCatMoveSync((CMovePBPtr) &pb); // ignore errors
} else {
// make unique1 point to file in dest
swapola = unique1Ptr;
unique1Ptr = unique2Ptr;
unique2Ptr = swapola;
}
// swap the catalog info by re-aiming the CInfoPB's
catInfoSource.hFileInfo.ioNamePtr = unique2Ptr;
catInfoDest.hFileInfo.ioNamePtr = unique1Ptr;
catInfoSource.hFileInfo.ioDirID = dest -> parID;
catInfoDest.hFileInfo.ioDirID = source -> parID;
// leave original mod dates w/each file
temp = catInfoSource.hFileInfo.ioFlMdDat;
catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
catInfoDest.hFileInfo.ioFlMdDat = temp;
// ignore errors
PBSetCatInfoSync(&catInfoSource);
PBSetCatInfoSync(&catInfoDest);
// rename unique2 back to dest
error1:
pb.ioParam.ioMisc = (Ptr) &(dest -> name);
pb.fileParam.ioNamePtr = unique2Ptr;
pb.fileParam.ioDirID = dest -> parID;
PBHRenameSync(&pb); // ignore errors
// rename unique1 back to source
error2:
pb.ioParam.ioMisc = (Ptr) &(source -> name);
pb.fileParam.ioNamePtr = unique1Ptr;
pb.fileParam.ioDirID = source -> parID;
PBHRenameSync(&pb); // ignore errors
}
return(error);
}