mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 13:45:27 +00:00
914 lines
26 KiB
C
914 lines
26 KiB
C
/*
|
|
** Apple Macintosh Developer Technical Support
|
|
**
|
|
** FSSpec compatibility functions.
|
|
**
|
|
** by Jim Luther, Apple Developer Technical Support Emeritus
|
|
**
|
|
** File: FSpCompat.c
|
|
**
|
|
** Copyright © 1992-1996 Apple Computer, Inc.
|
|
** All rights reserved.
|
|
**
|
|
** You may incorporate this sample code into your applications without
|
|
** restriction, though the sample code has been provided "AS IS" and the
|
|
** responsibility for its operation is 100% yours. However, what you are
|
|
** not permitted to do is to redistribute the source as "DSC Sample Code"
|
|
** after having made changes. If you're going to re-distribute the source,
|
|
** we require that you make it clear in the source that the code was
|
|
** descended from Apple Sample Code, but that you've made changes.
|
|
*/
|
|
|
|
/*
|
|
** If building application 68K code, set GENERATENODATA to 0 for faster code.
|
|
** If building stand-alone 68K code, set GENERATENODATA to 1 so globals
|
|
** (static variables) are not used.
|
|
*/
|
|
#define GENERATENODATA 0
|
|
|
|
#include <Types.h>
|
|
#include <Errors.h>
|
|
#include <LowMem.h>
|
|
#include <Gestalt.h>
|
|
#include <Resources.h>
|
|
#include <Script.h>
|
|
|
|
#define __COMPILINGMOREFILES
|
|
|
|
#include "MoreFilesExtras.h"
|
|
#include "FSpCompat.h"
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* local constants */
|
|
|
|
enum {
|
|
gestaltBugFixAttrsTwo = 'bugy',
|
|
gestaltFSpExchangeFilesCompatibilityFix = 26,
|
|
gestaltBugFixAttrsThree = 'bugx',
|
|
gestaltFSpCreateScriptSupportFix = 1
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* static prototypes */
|
|
|
|
|
|
#if !SystemSevenOrLater
|
|
static Boolean FSHasFSSpecCalls(void);
|
|
|
|
static Boolean QTHasFSSpecCalls(void);
|
|
#endif /* !SystemSevenOrLater */
|
|
|
|
#if !SystemSevenFiveOrLater
|
|
static Boolean HasFSpExchangeFilesCompatibilityFix(void);
|
|
#endif /* !SystemSevenFiveOrLater */
|
|
|
|
static Boolean HasFSpCreateScriptSupportFix(void);
|
|
|
|
#if !SystemSevenFiveOrLater
|
|
static OSErr GenerateUniqueName(short volume,
|
|
long *startSeed,
|
|
long dir1,
|
|
long dir2,
|
|
StringPtr uniqueName);
|
|
#endif /* !SystemSevenFiveOrLater */
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
|
|
|
|
#if !SystemSevenOrLater
|
|
static Boolean FSHasFSSpecCalls(void)
|
|
{
|
|
long response;
|
|
#if !GENERATENODATA
|
|
static Boolean tested = false;
|
|
static Boolean result = false;
|
|
#else
|
|
Boolean result = false;
|
|
#endif
|
|
|
|
#if !GENERATENODATA
|
|
if ( !tested )
|
|
{
|
|
tested = true;
|
|
#endif
|
|
if ( Gestalt(gestaltFSAttr, &response) == noErr )
|
|
{
|
|
result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
|
|
}
|
|
#if !GENERATENODATA
|
|
}
|
|
#endif
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
|
|
/* except for FSpExchangeFiles. */
|
|
|
|
#if !SystemSevenOrLater
|
|
static Boolean QTHasFSSpecCalls(void)
|
|
{
|
|
long response;
|
|
#if !GENERATENODATA
|
|
static Boolean tested = false;
|
|
static Boolean result = false;
|
|
#else
|
|
Boolean result = false;
|
|
#endif
|
|
|
|
#if !GENERATENODATA
|
|
if ( !tested )
|
|
{
|
|
tested = true;
|
|
#endif
|
|
result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
|
|
#if !GENERATENODATA
|
|
}
|
|
#endif
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
|
|
/* compatibility code has been fixed in system software. */
|
|
/* This was fixed by System Update 3.0, so if SystemSevenFiveOrLater */
|
|
/* is true, then we know the fix is in. */
|
|
|
|
#if !SystemSevenFiveOrLater
|
|
static Boolean HasFSpExchangeFilesCompatibilityFix(void)
|
|
{
|
|
long response;
|
|
#if !GENERATENODATA
|
|
static Boolean tested = false;
|
|
static Boolean result = false;
|
|
#else /* !GENERATENODATA */
|
|
Boolean result = false;
|
|
#endif /* !GENERATENODATA */
|
|
|
|
#if !GENERATENODATA
|
|
if ( !tested )
|
|
{
|
|
tested = true;
|
|
#endif /* !GENERATENODATA */
|
|
if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
|
|
{
|
|
result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
|
|
}
|
|
#if !GENERATENODATA
|
|
}
|
|
#endif /* !GENERATENODATA */
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenFiveOrLater */
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
|
|
/* FSpCreateResFile have been fixed in system software to correctly set */
|
|
/* the scriptCode in the volume's catalog. */
|
|
/* This was fixed by System 7.5 Update 1.0 */
|
|
|
|
static Boolean HasFSpCreateScriptSupportFix(void)
|
|
{
|
|
long response;
|
|
#if !GENERATENODATA
|
|
static Boolean tested = false;
|
|
static Boolean result = false;
|
|
#else
|
|
Boolean result = false;
|
|
#endif /* !GENERATENODATA */
|
|
|
|
#if !GENERATENODATA
|
|
if ( !tested )
|
|
{
|
|
tested = true;
|
|
#endif /* !GENERATENODATA */
|
|
if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
|
|
{
|
|
result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
|
|
}
|
|
#if !GENERATENODATA
|
|
}
|
|
#endif /* !GENERATENODATA */
|
|
return ( result );
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
** File Manager FSp calls
|
|
*/
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSMakeFSSpecCompat(short vRefNum,
|
|
long dirID,
|
|
ConstStr255Param fileName,
|
|
FSSpecPtr spec)
|
|
{
|
|
OSErr result;
|
|
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
/* Let the file system create the FSSpec if it can since it does the job */
|
|
/* much more efficiently than I can. */
|
|
result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
|
|
/* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
|
|
/* returned in the parID field when making an FSSpec to the volume's */
|
|
/* root directory by passing a full pathname in MakeFSSpec's */
|
|
/* fileName parameter. */
|
|
if ( (result == noErr) && (spec->parID == 0) )
|
|
spec->parID = fsRtParID;
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
Boolean isDirectory;
|
|
|
|
result = GetObjectLocation(vRefNum, dirID, (StringPtr)fileName,
|
|
&(spec->vRefNum), &(spec->parID), spec->name,
|
|
&isDirectory);
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
return ( result );
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpOpenDFCompat(const FSSpec *spec,
|
|
char permission,
|
|
short *refNum)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpOpenDF(spec, permission, refNum) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
OSErr result;
|
|
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 = NULL;
|
|
result = PBHOpenSync(&pb); /* OpenDF not supported by System 6, so use Open */
|
|
*refNum = pb.ioParam.ioRefNum;
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpOpenRFCompat(const FSSpec *spec,
|
|
char permission,
|
|
short *refNum)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpOpenRF(spec, permission, refNum) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
OSErr result;
|
|
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 = NULL;
|
|
result = PBHOpenRFSync(&pb);
|
|
*refNum = pb.ioParam.ioRefNum;
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpCreateCompat(const FSSpec *spec,
|
|
OSType creator,
|
|
OSType fileType,
|
|
ScriptCode scriptTag)
|
|
{
|
|
OSErr result;
|
|
UniversalFMPB pb;
|
|
|
|
/* There's no conditional to test for, so this test must be made */
|
|
if ( HasFSpCreateScriptSupportFix() )
|
|
{
|
|
return ( FSpCreate(spec, creator, fileType, scriptTag) );
|
|
}
|
|
/* If FSpCreate isn't called, this code will be executed */
|
|
pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
|
|
pb.hPB.fileParam.ioDirID = spec->parID;
|
|
pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
|
|
pb.hPB.fileParam.ioFVersNum = 0;
|
|
result = PBHCreateSync(&(pb.hPB));
|
|
if ( result == noErr )
|
|
{
|
|
/* get info on created item */
|
|
pb.ciPB.hFileInfo.ioFDirIndex = 0;
|
|
result = PBGetCatInfoSync(&(pb.ciPB));
|
|
if ( result == noErr )
|
|
{
|
|
/* Set fdScript in FXInfo */
|
|
/* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
|
|
/* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
|
|
/* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
|
|
pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
|
|
((char)scriptTag | (char)0x80) :
|
|
(smRoman);
|
|
/* Set creator/fileType */
|
|
pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
|
|
pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
|
|
/* Restore ioDirID field in pb which was changed by PBGetCatInfo */
|
|
pb.ciPB.hFileInfo.ioDirID = spec->parID;
|
|
result = PBSetCatInfoSync(&(pb.ciPB));
|
|
}
|
|
}
|
|
return ( result );
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpDirCreateCompat(const FSSpec *spec,
|
|
ScriptCode scriptTag,
|
|
long *createdDirID)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpDirCreate(spec, scriptTag, createdDirID) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
OSErr result;
|
|
UniversalFMPB pb;
|
|
|
|
pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
|
|
pb.hPB.fileParam.ioDirID = spec->parID;
|
|
pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
|
|
result = PBDirCreateSync(&(pb.hPB));
|
|
*createdDirID = pb.hPB.fileParam.ioDirID;
|
|
if ( result == noErr )
|
|
{
|
|
/* get info on created item */
|
|
pb.ciPB.dirInfo.ioFDirIndex = 0;
|
|
pb.ciPB.dirInfo.ioDrDirID = spec->parID;
|
|
result = PBGetCatInfoSync(&(pb.ciPB));
|
|
if ( result == noErr )
|
|
{
|
|
/* Set frScript in DXInfo */
|
|
/* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
|
|
/* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
|
|
/* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
|
|
pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
|
|
((char)scriptTag | (char)0x80) :
|
|
(smRoman);
|
|
/* Restore ioDirID field in pb which was changed by PBGetCatInfo */
|
|
pb.ciPB.dirInfo.ioDrDirID = spec->parID;
|
|
result = PBSetCatInfoSync(&(pb.ciPB));
|
|
}
|
|
}
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpDeleteCompat(const FSSpec *spec)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpDelete(spec) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
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) );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpGetFInfoCompat(const FSSpec *spec,
|
|
FInfo *fndrInfo)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpGetFInfo(spec, fndrInfo) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
OSErr result;
|
|
HParamBlockRec pb;
|
|
|
|
pb.fileParam.ioVRefNum = spec->vRefNum;
|
|
pb.fileParam.ioDirID = spec->parID;
|
|
pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
|
|
pb.fileParam.ioFVersNum = 0;
|
|
pb.fileParam.ioFDirIndex = 0;
|
|
result = PBHGetFInfoSync(&pb);
|
|
*fndrInfo = pb.fileParam.ioFlFndrInfo;
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpSetFInfoCompat(const FSSpec *spec,
|
|
const FInfo *fndrInfo)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpSetFInfo(spec, fndrInfo) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
OSErr result;
|
|
HParamBlockRec pb;
|
|
|
|
pb.fileParam.ioVRefNum = spec->vRefNum;
|
|
pb.fileParam.ioDirID = spec->parID;
|
|
pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
|
|
pb.fileParam.ioFVersNum = 0;
|
|
pb.fileParam.ioFDirIndex = 0;
|
|
result = PBHGetFInfoSync(&pb);
|
|
if ( result == noErr )
|
|
{
|
|
pb.fileParam.ioFlFndrInfo = *fndrInfo;
|
|
pb.fileParam.ioDirID = spec->parID;
|
|
result = PBHSetFInfoSync(&pb);
|
|
}
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpSetFLockCompat(const FSSpec *spec)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpSetFLock(spec) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
HParamBlockRec pb;
|
|
|
|
pb.fileParam.ioVRefNum = spec->vRefNum;
|
|
pb.fileParam.ioDirID = spec->parID;
|
|
pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
|
|
pb.fileParam.ioFVersNum = 0;
|
|
return ( PBHSetFLockSync(&pb) );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpRstFLockCompat(const FSSpec *spec)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpRstFLock(spec) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
HParamBlockRec pb;
|
|
|
|
pb.fileParam.ioVRefNum = spec->vRefNum;
|
|
pb.fileParam.ioDirID = spec->parID;
|
|
pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
|
|
pb.fileParam.ioFVersNum = 0;
|
|
return ( PBHRstFLockSync(&pb) );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpRenameCompat(const FSSpec *spec,
|
|
ConstStr255Param newName)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpRename(spec, newName) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
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) );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpCatMoveCompat(const FSSpec *source,
|
|
const FSSpec *dest)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpCatMove(source, dest) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
CMovePBRec pb;
|
|
|
|
/* source and destination volume must be the same */
|
|
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) );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
|
|
/* on the specified volume. Ripped off from Feldman's code. */
|
|
|
|
#if !SystemSevenFiveOrLater
|
|
static OSErr GenerateUniqueName(short volume,
|
|
long *startSeed,
|
|
long dir1,
|
|
long dir2,
|
|
StringPtr uniqueName)
|
|
{
|
|
OSErr error = noErr;
|
|
long i;
|
|
CInfoPBRec cinfo;
|
|
unsigned char hexStr[16];
|
|
|
|
for ( i = 0; i < 16; ++i )
|
|
{
|
|
if ( i < 10 )
|
|
hexStr[i] = 0x30 + i;
|
|
else
|
|
hexStr[i] = 0x37 + i;
|
|
}
|
|
|
|
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] = hexStr[((*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 );
|
|
}
|
|
#endif /* !SystemSevenFiveOrLater */
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal OSErr FSpExchangeFilesCompat(const FSSpec *source,
|
|
const FSSpec *dest)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
#if !SystemSevenFiveOrLater
|
|
if ( HasFSpExchangeFilesCompatibilityFix() )
|
|
#endif /* !SystemSevenFiveOrLater */
|
|
{
|
|
return ( FSpExchangeFiles(source, dest) );
|
|
}
|
|
}
|
|
#if !SystemSevenFiveOrLater
|
|
/* If FSpExchangeFiles isn't called, this code will be executed */
|
|
{
|
|
HParamBlockRec pb;
|
|
CInfoPBRec catInfoSource, catInfoDest;
|
|
OSErr result, result2;
|
|
Str31 unique1, unique2;
|
|
StringPtr unique1Ptr, unique2Ptr, swapola;
|
|
GetVolParmsInfoBuffer volInfo;
|
|
long theSeed, temp;
|
|
|
|
/* Make sure the source and destination are on the same volume */
|
|
if ( source->vRefNum != dest->vRefNum )
|
|
{
|
|
result = diffVolErr;
|
|
goto errorExit3;
|
|
}
|
|
|
|
/* Try PBExchangeFiles first since it preserves the file ID reference */
|
|
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;
|
|
|
|
result = PBExchangeFilesSync(&pb);
|
|
|
|
/* Note: The compatibility case won't work for files with *Btree control blocks. */
|
|
/* Right now the only *Btree files are created by the system. */
|
|
if ( result != noErr )
|
|
{
|
|
pb.ioParam.ioNamePtr = NULL;
|
|
pb.ioParam.ioBuffer = (Ptr) &volInfo;
|
|
pb.ioParam.ioReqCount = sizeof(volInfo);
|
|
result2 = PBHGetVolParmsSync(&pb);
|
|
|
|
/* continue if volume has no fileID support (or no GetVolParms support) */
|
|
if ( (result2 == noErr) && hasFileIDs(volInfo) )
|
|
goto errorExit3;
|
|
|
|
/* Get the catalog information for each file */
|
|
/* and make sure both files are *really* files */
|
|
catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
|
|
catInfoSource.hFileInfo.ioFDirIndex = 0;
|
|
catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
|
|
catInfoSource.hFileInfo.ioDirID = source->parID;
|
|
catInfoSource.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
|
|
result = PBGetCatInfoSync(&catInfoSource);
|
|
if ( result != noErr )
|
|
goto errorExit3;
|
|
if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
|
|
{
|
|
result = notAFileErr;
|
|
goto errorExit3;
|
|
}
|
|
|
|
catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
|
|
catInfoDest.hFileInfo.ioFDirIndex = 0;
|
|
catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
|
|
catInfoDest.hFileInfo.ioDirID = dest->parID;
|
|
catInfoDest.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
|
|
result = PBGetCatInfoSync(&catInfoDest);
|
|
if ( result != noErr )
|
|
goto errorExit3;
|
|
if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
|
|
{
|
|
result = notAFileErr;
|
|
goto errorExit3;
|
|
}
|
|
|
|
/* generate 2 filenames that are unique in both directories */
|
|
theSeed = 0x64666A6C; /* a fine unlikely filename */
|
|
unique1Ptr = (StringPtr)&unique1;
|
|
unique2Ptr = (StringPtr)&unique2;
|
|
|
|
result = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
|
|
if ( result != noErr )
|
|
goto errorExit3;
|
|
|
|
GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
|
|
if ( result != noErr )
|
|
goto errorExit3;
|
|
|
|
/* rename source to unique1 */
|
|
pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
|
|
pb.ioParam.ioMisc = (Ptr) unique1Ptr;
|
|
pb.ioParam.ioVersNum = 0;
|
|
result = PBHRenameSync(&pb);
|
|
if ( result != noErr )
|
|
goto errorExit3;
|
|
|
|
/* rename dest to unique2 */
|
|
pb.ioParam.ioMisc = (Ptr) unique2Ptr;
|
|
pb.ioParam.ioVersNum = 0;
|
|
pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
|
|
pb.fileParam.ioDirID = dest->parID;
|
|
result = PBHRenameSync(&pb);
|
|
if ( result != noErr )
|
|
goto errorExit2; /* back out gracefully by renaming unique1 back to source */
|
|
|
|
/* If files are not in same directory, swap their locations */
|
|
if ( source->parID != dest->parID )
|
|
{
|
|
/* move source file to dest directory */
|
|
pb.copyParam.ioNamePtr = unique1Ptr;
|
|
pb.copyParam.ioNewName = NULL;
|
|
pb.copyParam.ioNewDirID = dest->parID;
|
|
pb.copyParam.ioDirID = source->parID;
|
|
result = PBCatMoveSync((CMovePBPtr) &pb);
|
|
if ( result != noErr )
|
|
goto errorExit1; /* back out gracefully by renaming both files to original names */
|
|
|
|
/* move dest file to source directory */
|
|
pb.copyParam.ioNamePtr = unique2Ptr;
|
|
pb.copyParam.ioNewDirID = source->parID;
|
|
pb.copyParam.ioDirID = dest->parID;
|
|
result = PBCatMoveSync((CMovePBPtr) &pb);
|
|
if ( result != noErr)
|
|
{
|
|
/* life is very bad. We'll at least try to move source back */
|
|
pb.copyParam.ioNamePtr = unique1Ptr;
|
|
pb.copyParam.ioNewName = NULL;
|
|
pb.copyParam.ioNewDirID = source->parID;
|
|
pb.copyParam.ioDirID = dest->parID;
|
|
(void) PBCatMoveSync((CMovePBPtr) &pb); /* ignore errors */
|
|
goto errorExit1; /* back out gracefully by renaming both files to original names */
|
|
}
|
|
}
|
|
|
|
/* Make unique1Ptr point to file in source->parID */
|
|
/* and unique2Ptr point to file in dest->parID */
|
|
/* This lets us fall through to the rename code below */
|
|
swapola = unique1Ptr;
|
|
unique1Ptr = unique2Ptr;
|
|
unique2Ptr = swapola;
|
|
|
|
/* At this point, the files are in their new locations (if they were moved) */
|
|
/* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
|
|
/* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
|
|
/* Need to swap attributes except mod date and swap names */
|
|
|
|
/* swap the catalog info by re-aiming the CInfoPB's */
|
|
catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
|
|
catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
|
|
|
|
catInfoSource.hFileInfo.ioDirID = source->parID;
|
|
catInfoDest.hFileInfo.ioDirID = dest->parID;
|
|
|
|
/* Swap the original mod dates with each file */
|
|
temp = catInfoSource.hFileInfo.ioFlMdDat;
|
|
catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
|
|
catInfoDest.hFileInfo.ioFlMdDat = temp;
|
|
|
|
/* Here's the swap (ignore errors) */
|
|
(void) PBSetCatInfoSync(&catInfoSource);
|
|
(void) PBSetCatInfoSync(&catInfoDest);
|
|
|
|
/* rename unique2 back to dest */
|
|
errorExit1:
|
|
pb.ioParam.ioMisc = (Ptr) &(dest->name);
|
|
pb.ioParam.ioVersNum = 0;
|
|
pb.fileParam.ioNamePtr = unique2Ptr;
|
|
pb.fileParam.ioDirID = dest->parID;
|
|
(void) PBHRenameSync(&pb); /* ignore errors */
|
|
|
|
/* rename unique1 back to source */
|
|
errorExit2:
|
|
pb.ioParam.ioMisc = (Ptr) &(source->name);
|
|
pb.ioParam.ioVersNum = 0;
|
|
pb.fileParam.ioNamePtr = unique1Ptr;
|
|
pb.fileParam.ioDirID = source->parID;
|
|
(void) PBHRenameSync(&pb); /* ignore errors */
|
|
}
|
|
errorExit3: { /* null statement */ }
|
|
return ( result );
|
|
}
|
|
#endif /* !SystemSevenFiveOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
** Resource Manager FSp calls
|
|
*/
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal short FSpOpenResFileCompat(const FSSpec *spec,
|
|
SignedByte permission)
|
|
{
|
|
#if !SystemSevenOrLater
|
|
if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
|
|
#endif /* !SystemSevenOrLater */
|
|
{
|
|
return ( FSpOpenResFile(spec, permission) );
|
|
}
|
|
#if !SystemSevenOrLater
|
|
else
|
|
{
|
|
return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
|
|
}
|
|
#endif /* !SystemSevenOrLater */
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
pascal void FSpCreateResFileCompat(const FSSpec *spec,
|
|
OSType creator,
|
|
OSType fileType,
|
|
ScriptCode scriptTag)
|
|
{
|
|
if ( HasFSpCreateScriptSupportFix() )
|
|
{
|
|
FSpCreateResFile(spec, creator, fileType, scriptTag);
|
|
return;
|
|
}
|
|
/* If FSpCreateResFile isn't called, this code will be executed */
|
|
{
|
|
OSErr result;
|
|
CInfoPBRec pb;
|
|
|
|
HCreateResFile(spec->vRefNum, spec->parID, spec->name);
|
|
if ( ResError() == noErr )
|
|
{
|
|
/* get info on created item */
|
|
pb.hFileInfo.ioVRefNum = spec->vRefNum;
|
|
pb.hFileInfo.ioDirID = spec->parID;
|
|
pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
|
|
pb.hFileInfo.ioFDirIndex = 0;
|
|
result = PBGetCatInfoSync(&pb);
|
|
if ( result == noErr )
|
|
{
|
|
/* Set fdScript in FXInfo */
|
|
/* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
|
|
/* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
|
|
/* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
|
|
pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
|
|
((char)scriptTag | (char)0x80) :
|
|
(smRoman);
|
|
/* Set creator/fileType */
|
|
pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
|
|
pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
|
|
|
|
/* Restore ioDirID field in pb which was changed by PBGetCatInfo */
|
|
pb.hFileInfo.ioDirID = spec->parID;
|
|
result = PBSetCatInfoSync(&pb);
|
|
}
|
|
/* Set ResErr low memory global to result */
|
|
LMSetResErr(result);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|