mac-rom/Toolbox/AliasMgr/alExt.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

2265 lines
82 KiB
C

/*
File: alExt.c
Contains: External interfaces for alias manager.
Written by: Prashant Patel
Copyright: © 1989-1991 by Apple Computer, Inc., all rights reserved.
This file is used in these builds: BigBang
Change History (most recent first):
<42> 2/27/91 PP ich,#ich-AMgr-0095:Allow ejectable FileShared volumes to be auto
mounted from client side.
<41> 2/11/91 PP ich,<go5 Decision>:Do not allow CanonifyFile to work for an MFS
volume. Remove any MFS Volume alias support (files within volume
work). ich,#ich-AMgr-0094:Hints for null filenames are invalid.
<40> 2/5/91 stb gs: fix casing
<39> 1/31/91 PP ich,#b4q4 WhiteBoard:FSMakeFSSpec does not work for MFS volume
itself. Use the old AL_canonifyFile whenever MakeFSSpec fails.
<38> 1/25/91 PP ich,#81507:FollowFinderAlias gives priority to original volume
mounting over relative path target in same folder.
FollowFinderAlias is now an internal trap selector so Finder can
call and use the same algorithm. It has an additional logon
parameter.
<37> 1/22/91 PP ich,#ICH-AMGR-0089:In GetNextSpec call, FollowFinderAlias is
called with a copy of target as fromFile.
<36> 1/11/91 PP (ich) Set relative path search hint only if it is valid.
<35> 1/10/91 PP (ich) In ResolveAliasFile, handle end case of 10 chain alias
correctly. Kind is correctly checked for minimal fullpath
aliases. In ResolveAliasFile, isAlias bit is ignored for
folders. For FileShare aliases, if remote info switch occurs,
reassign hint parent dir. For multiple volume search, preserve
the original target's volume ref num.
<34> 1/2/91 PP (ich) CatSearch time out is in miliseconds. Fix bug related to
optimization of not slow searching already searched volume.
<33> 12/21/90 LN change constStrxxxParameter to ConstStrxxxParam as per change in
Types.h
<32> 12/20/90 PP (ich) Force an update of alias if alias has moved instead of
target for ResolveAliasFile call. FilterFile moved here from
alUtil.c. UpdateAList is split into NewCandidate and
AddCandidate. useCanceledErr does not conflict with found
candidates.
<31> 12/13/90 PP (PP/ngk) Ignore UpdateAlias result code in ResolveAlias if
MatchAlias was successful and still return target. (ich) Do slow
search on volume aliases correctly. Minimal fullpath does
additional param checking. In StoreHint, check for bad vref and
for bad dirID always return dirNFErr. During multiple volume and
fast searches, do not update needsUpdate if found count has not
changed. Call to FSMakeFSSpec is moved to AL_canonifyFile.
<30> 11/29/90 PP (PP/ngk) In StoreHint, if relative first search cannot return a
hint (i.e. no relative path stored or other error), still try to
return a hint if other search rule was specified. (PP/ich)
ResolveAliasFile should follow exactly same algorithm for
finding targets as Finder does. Return hint for afpAccessDenied
files. Remove alias record version 1 compatibility code.
<29> 10/30/90 PP AL_isItSelf is made external. If relative had priority but found
by absolute, do not set needsUpdate if the fromFile and Target
volumes are different. If resolving a server alias on client, do
not do FastSearch on switched auxiliary data but try to check if
root volume is mounted.
<28> 10/21/90 gbm Change hfileInfo to hFileInfo for the last time (plus one).
<28> 10/10/90 JL Change hfileInfo to hFileInfo for the last time.
<27> 10/10/90 PP For creation dates on AppleShare volumes, need to store raw data
instead of time adjusted to current machine's date.
ResolveAliasFile returns resNotFound if alias bit is set but no
alias resource. StoreHint returns correct vRefNum for relative
first search.
<26> 9/1/90 PP When relative path found a wrong kind match, reset the volume
flag to force a find volume. If MakeFSSpec fails, try
CanonifyFile.
<25> 8/29/90 PP If during relative search, nothing was added to found list,
search for the target volume. For minimal fullpath aliases, if
the path ends in a colon, make it a directory alias.
<24> 8/28/90 dnf Change calls to CatSearch to use new param block names
(ioSearchBits, ioSearchInfo1, ioSearchInfo2)
<23> 8/17/90 PP Fast Search on multiple volumes mean search by ID followed by
search by name in parent directory. Volume creation date cannot
be ontained by calling GetCatInfo on dirID of 2.
<22> 8/10/90 PP Fix bug related to resolving aliases for renamed volume targets.
<21> 8/10/90 PP Handle MFS volume aliases in ResolveAliasFile.
<20> 8/7/90 PP Suppress warnings in AliasVolumeMount.
<19> 8/6/90 PP Support auto volume mount for foreign file systems other than
AppleShare. If fromFile is set for ResolveAlias, do relative
search first.
<18> 7/19/90 PP When FileShare returns info about next shared folder, check it's
name and creation date against the info in alias record. If
relative has first priority and found by absolute, set
needsUpdate.
<17> 7/11/90 PP Fix bug in ResolveAliasFile related to returning targetIsFolder
correctly when resolveAliasChains is false.
<16> 7/9/90 PP Fix bug related to returning needsUpdate true if the candidate
buffer is greater than 1.
<15> 7/2/90 PP Add ResolveFinderAlias. Adopted from Ian Hendry's routine for
DTS Goodies disk.
<14> 6/28/90 PP Convert CanonicalFileSpec to FSSpec.
<13> 6/15/90 PP Remove "SelectAlias" feature. Correctly compute IsItSelf if
there are no bridges.
<12> 5/31/90 PP For aliases to volumes, optimize the resolution. Fix a bug
related to leaf name greater than 63 chars for fullpath minimal
alias.
<11> 5/16/90 PP FileShare CreateID works. Undef code that uses it.
<10> 5/3/90 PP Closer integration of FileShare and aliases. Incorporate Diet
Clinic tips.
<9> 4/10/90 PP Change once more hFileInfo to hfileInfo to stay consistent with
Files.h
<8> 4/5/90 PP Code size optimization. Support kARMsearchRelFirst and return
hint when alias not resolved.
<7> 3/8/90 PP Implement NewAliasMinimal and NewAliasMinimalFromFullPath.
Change "hfileInfo" to "hFileInfo'" to match Files.h change.
<6> 2/27/90 PP AppleShare foreign volumes should not become fuzzy if creation
date has changed.
<5> 2/6/90 PP Fix messed up comments during last check-in.
<4> 2/6/90 PP No SelectAlias dialog for volume aliases. For HFS volumes,
match resolved aliases to be same kind (file or directory).
<3> 1/21/90 PP Add support for HD and Ejectable volumes auto mount. Store
driver name for ejectable non-floppy volumes in alias record.
Fix relative path returning wrong type bug. Add concept of
fuzzy volume.
<2.8> 12/15/89 prp Fix CanonifyFile bug for MFS disks. Make ValidateHandle calls.
<2.7> 11/27/89 prp Fix incorrect dirID returned for AbsPath CanonifyFile call.
<2.6> 11/16/89 prp MatchAlias sets needsUpdate correctly if multiple answers are
returned or if one answer on different volume is returned.
SelectAlias mounts the volume automatically.Resolve or Select
for relative path aliases mounts the volumes correctly.
<2.5> 10/30/89 prp ¥ In MatchAlias, call file filter for fast matches also. ¥ Use
AL_findVolume routine to find the volume correctly. ¥
AL_findByID can return fnfErr for directories. Handling this
corrects the bug related finding directories whose dirIDs have
changed. ¥ For files/directories fast search, use the absolute
path search correctly. ¥ SelectAlias calls MatchAlias with
correct filter proc params instead of NULL. ¥ SelectAlias
returns nsvErr if the volume is not mounted for a volume alias.
<2.4> 10/17/89 prp Aliases did not work on 68000 machines. Fixed odd addressing in
variable length info structure.
<2.3> 10/13/89 prp Handle NULL as well as zero length input for Filename for
CanonifyFile call.
<2.2> 10/2/89 prp Added 'GetAliasInfo' routine.
<2.1> 9/18/89 prp UpdateAlias, MatchAlias and SelectAlias has a new API with
additional parameters.
<2.0> 9/6/89 prp Added DisposeAlias back until DPMgr is in sync.
<1.9> 9/6/89 prp Changes from CodeReview.
<1.8> 8/11/89 prp Handle eofErr as a valid legal error from CatSearch.
<1.7> 8/7/89 prp Add SelectAlias with dialog support. Add automatic volume mount
support.
<1.6> 6/23/89 prp Variable names "server" and "zone" changed to "serverName" and
"zoneName" in order to avoid conflict with globally defined
symbols in the BigBang build.
<1.5> 6/12/89 prp In CanonifyFile, if the file name does not exist, return fnfErr
in addition to correct canonical form.
<1.4> 6/12/89 prp CanonifyFile handles all different cases. No HPurge and MoveHH
in New and Update. No separate emphasize relative path bit.
Consolidated New and Update routines. Added slow search. Cleaned
up IFNDEFs.
<1.3> 6/6/89 prp In MatchAlias, EqualString test was inverted. Also, during
UpdateAlias, if an error occurs, do not dispose of the alias
handle.
<1.2> 6/1/89 prp Make sure ioNamePtr is always assigned some value before a
'PB...' file manager call is made.
<1.1> 5/31/89 prp Moved AliasRecord to private definition file.
<1.0> 5/30/89 prp Initial release
To Do:
*/
/*EASE$$$ READ ONLY COPY of file ÒalExt.cÓ
** 2.8 prp 12/15/1989 Fix CanonifyFile bug for MFS disks. Make ValidateHandle
** calls.
** 2.7 prp 11/27/1989 Fix incorrect dirID returned for AbsPath CanonifyFile
** call.
** 2.6 prp 11/16/1989 MatchAlias sets needsUpdate correctly if multiple
** answers are returned or if one answer on different volume is
** returned. SelectAlias mounts the volume automatically.Resolve or
** Select for relative path aliases mounts the volumes correctly.
** 2.5 prp 10/30/1989 ¥ In MatchAlias, call file filter for fast matches also.
** ¥ Use AL_findVolume routine to find the volume correctly. ¥
** AL_findByID can return fnfErr for directories. Handling this corrects
** the bug related finding directories whose dirIDs have changed. ¥ For
** files/directories fast search, use the absolute path search
** correctly. ¥ SelectAlias calls MatchAlias with correct filter proc
** params instead of NULL. ¥ SelectAlias returns nsvErr if the volume is
** not mounted for a volume alias.
** 2.4 prp 10/17/1989 Aliases did not work on 68000 machines. Fixed odd
** addressing in variable length info structure.
** 2.3 prp 10/13/1989 Handle NULL as well as zero length input for Filename
** for CanonifyFile call.
** 2.2 prp 10/02/1989 Added 'GetAliasInfo' routine.
** 2.1 prp 09/18/1989 UpdateAlias, MatchAlias and SelectAlias has a new API
** with additional parameters.
** 2.0 prp 09/06/1989 Added DisposeAlias back until DPMgr is in sync.
** 1.9 prp 09/06/1989 Changes from CodeReview.
** 1.8 prp 08/11/1989 Handle eofErr as a valid legal error from CatSearch.
** 1.7 prp 08/07/1989 Add SelectAlias with dialog support. Add automatic
** volume mount support.
** 1.6 prp 06/23/1989 Variable names "server" and "zone" changed to
** "serverName" and "zoneName" in order to avoid conflict with globally
** defined symbols in the BigBang build.
** 1.5 prp 06/12/1989 In CanonifyFile, if the file name does not exist, return
** fnfErr in addition to correct canonical form.
** 1.4 prp 06/12/1989 CanonifyFile handles all different cases. No HPurge and
** MoveHH in New and Update. No separate emphasize relative path bit.
** Consolidated New and Update routines. Added slow search. Cleaned up
** IFNDEFs.
** 1.3 prp 06/06/1989 In MatchAlias, EqualString test was inverted. Also,
** during UpdateAlias, if an error occurs, do not dispose of the alias
** handle.
** 1.2 prp 06/01/1989 Make sure ioNamePtr is always assigned some value before
** a 'PB...' file manager call is made.
** 1.1 prp 05/31/1989 Moved AliasRecord to private definition file.
** 1.0 prp 05/30/1989 Initial release
** END EASE MODIFICATION HISTORY */
/*********************************************************************
*
* File: alExt.c
* Project: Alias Manager
* Contains: external interfaces
* Written by: Prashant Patel
*
* Copyright 1989 by Apple Computer, Inc.
* All Rights Reserved.
*
**********************************************************************/
/**********************************************************************
*************** Public Include files *******************
*********************************************************************/
#include "Aliases.h"
/**********************************************************************
*************** Private Include files *******************
*********************************************************************/
#include "aliasPriv.h"
/**********************************************************************
*************** External C Include files ***************
*********************************************************************/
#ifndef __MEMORY__
#include <Memory.h>
#endif
#ifndef __FILES__
#include <files.h>
#endif
#ifndef __EVENTS__
#include <Events.h>
#endif
#ifndef __ERRORS__
#include <errors.h>
#endif
#ifndef __STRING__
#include <String.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __OSUTILS__
#include <OSUtils.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __DEVICES__
#include <Devices.h>
#endif
#ifndef __SYSEQU__
#include <SysEqu.h>
#endif
/*********************************************************************
******** private definitions ****************************************
*********************************************************************/
/* match alias search kind */
enum { kFindByID, // find by directory ID or file ID
kFindByName, // find by name in parent directory
kFindByNum, // find by file number in parent directory
kFindByAbsPath, // find by absolute path
kFindByRelPath // find by relative path
};
typedef short MatchAliasSearchKind;
typedef struct {
// MatchAlias input parameters
const FSSpec *fromFile; // aliased from file
unsigned long rulesMask; // search rules mask
short aliasCount; // # of entries in alias list
FSSpecPtr aliasList; // alias list buffer
Boolean needsUpdate; // does alias needs updating?
AliasFilterProcPtr aliasFilter; // filter proc for alias match
Ptr yourDataPtr; // a data param passed to filter proc
// local variables in the structure
AliasPtrPriv aptr; // pointer to locked AliasRecord
short vref; // volume ref num of mounted volume
short curCnt; // current output alias list count
long newParentDir; // target's new parent's directory ID
Str63 newTargetName; // new name of traget
long newFileNum; // new file number of the target
long hintParentDirAbs; // if not found, location of possible parent directory for absolute searches
long hintParentDirRel; // if not found, location of possible parent directory for relative searches
Boolean quitFlag; // quit the search, client filter tells us so
Boolean isVolumeFuzzy; // Is found volume fuzzy? meaning different creation date
Boolean foundByName; // Did we find the match by name in parent directory?
Boolean foundByRelativeFirst; // Was target found by relative search first or direct serach?
/* following variables are used during slow search of a volume. */
Boolean CatSearchAvailable; // Is CatSearch available?
CatPositionRec prec; // CatSearch IO position record
long curDir; // current directory that we are searching, start at root
short curIdx; // current index into directory stack
short curIoFDirIndex; // current index into the directory being searched
LongsHandle dirStack; // directory stack
/* following variables are used for handling shared volumes (FileShare type) */
AuxAliasInfo auxAliasRecord; // auxiliary alias record
Boolean auxAliasSwitch; // Did we switch to auxiliary alias record?
Boolean auxRealDirSwitch; // Did we switch to auxiliary real parent dirID?
Boolean searchedAllVols; // Did search all volumes on the server side?
Boolean volumeAliasFuzzy; // Should extra checks be required for volume aliases?
} MatchAliasParamBlk;
#define SCGetExpFldr 6; // Get Exported Folder info
/**********************************************************************
*************** Private Macros ***************************
*********************************************************************/
/*** exit the routine if input buffer is full or quitFlag by client is set ***/
#define mExitIfQuitOrBufFull(quitFlag, cnt,lim) \
if (quitFlag || (cnt >= lim)) \
goto EXIT;
/**********************************************************************
*** Create a new alias (common for real, minimal and minimal
from fullpath) ***********************
*********************************************************************/
static pascal OSErr AL_newAliasCommon( const FSSpec *fromFile, //I aliased from file
const FSSpec *target, //I aliased to file
AliasHandlePriv *alias, //O alias record handle
NewAliasType type, //I what type of new alias
MinimalFullpathSpec *fullpath) //I fullpath spec
{
OSErr err; // result code
Boolean dummy; // dummy wasChanged flag not needed during NewAlias creation
*alias = (AliasHandlePriv) NewHandleClear(sizeof(AliasRecordPriv));
if (*alias == NULL) // no heap space
return (MemError());
err = AL_fillAlias (fromFile, target, kCreateAlias, *alias, &dummy, type, fullpath);
if (err != noErr) {
DisposHandle((Handle)*alias); // fatal error, return NULL
*alias = NULL;
}
return (err);
} // end of AL_newAliasCommon routine
/**********************************************************************
*************** Create a new alias ***********************
*********************************************************************/
pascal OSErr AL_newAlias( const FSSpec *fromFile, //I aliased from file
const FSSpec *target, //I aliased to file
AliasHandlePriv *alias) //O alias record handle
{
return (AL_newAliasCommon(fromFile, target, alias, kCompleteAlias, NULL));
} // end of AL_newAlias routine
/**********************************************************************
*************** Create a minimal new alias ***************
*********************************************************************/
pascal OSErr AL_newAliasMinimal(const FSSpec *target, //I aliased to file
AliasHandlePriv *alias) //O alias record handle
{
return (AL_newAliasCommon(NULL, target, alias, kMinimalAlias, NULL));
} // end of AL_newAliasMinimal routine
/**********************************************************************
*************** Create a minimal new alias from fullpath *************
*********************************************************************/
pascal OSErr AL_newAliasMinimalFromFullpath(short fullpathLength, //I length of fullpath
const unsigned char *fullpath, //I fullpath
const Str32 zoneName, //I zone name
const Str31 serverName, //I server name
AliasHandlePriv *alias) //O alias record handle
{
OSErr err; // result code
FSSpec target; // a dummy target set up for NewAlias
MinimalFullpathSpec minimalFullpath; // pass the fullpath spec to NewAlias
Str255 name; // fileName/volumeName from the given path
if (fullpath == NULL || fullpathLength <= 0 || !AL_isFullpath(fullpath, fullpathLength) ||
(zoneName != NULL && Length(zoneName) > (sizeof(Str32)-1)) ||
(serverName != NULL && Length(serverName) > (sizeof(Str31)-1)))
return (paramErr);
target.vRefNum = 0;
target.parID = kInvalidValue;
AL_getFilename (fullpath, fullpathLength, name); // get the filename component
if (Length(name) > (sizeof(Str63)-1)) // make sure leaf is valid
return (paramErr);
AL_copyPString(name, target.name);
// store volume name from full path name
AL_getVolname (fullpath, fullpathLength, name); // get volume name
if (Length(name) > (sizeof(Str27)-1)) // make sure volume name is valid
return (paramErr);
minimalFullpath.fullpathLength = fullpathLength;
minimalFullpath.fullpath = fullpath;
minimalFullpath.zoneName = zoneName;
minimalFullpath.serverName = serverName;
err = AL_newAliasCommon(NULL, &target, alias, kMinimalFromFullpathAlias, &minimalFullpath);
/* Case where fullpath ends in a colon or a series of colons,
Mark the alias as a directory alias. */
if (err == noErr && Length(target.name) == 0)
(**alias)->thisAliasKind = kDirAlias;
return (err);
} // end of AL_newAliasMinimalFromFullpath routine
/**********************************************************************
*************** Resolve an alias ***************************
*********************************************************************/
pascal OSErr AL_resolveAlias(const FSSpec *fromFile, //I aliased from file
AliasHandlePriv alias, //I/O alias record handle
FSSpec *target, //O resolved alias FSSpec
Boolean *wasChanged) //O did any thing change?
{
OSErr err; // result code
short cnt = 1; // alias list length
unsigned long rulesMask;// rules to be passed to MatchAlias
/* This is a fast resolve. Do a fast search for the alias and find the only
one. Not interested in multiple ones. If the alias is found but
something has changed in the alias record, update the record. */
rulesMask = kARMMountVol | kARMSearch; // always do fast direct search and auto mount volumes
if (fromFile != NULL) // If requested, set priority for relative search
rulesMask |= kARMSearchRelFirst;
err = MatchAlias (fromFile, rulesMask, (AliasHandle)alias, &cnt, target, wasChanged, NULL, NULL);
if ((err == noErr) && *wasChanged) // found the alias. if changed, update the record
(void) UpdateAlias (fromFile, target, (AliasHandle)alias, wasChanged);
return (err);
} // end of ResolveAlias routine
/*********************************************************************
*************** Do alias kind and macthed entry kind match? *****
*********************************************************************/
static Boolean KindMatches(CInfoPBRec *cpbPtr, //I
const AliasPtrPriv aptr) //I
{
if (cpbPtr->hFileInfo.ioFlAttrib & kDirMask) {
if (aptr->thisAliasKind == kDirAlias)
return (TRUE);
} else if (aptr->thisAliasKind == kFileAlias)
return (TRUE);
return (FALSE);
} // end of KindMatches routine
/*********************************************************************
*************** Check if alias record attributes match CPB data **
*********************************************************************/
static Boolean AttributesMatch (register const AliasPtrPriv aptr, //I alias record pointer
register const CInfoPBRec *cpb, //I result of a CatInfo call
Boolean matchFileNum) //I should routine give priority to file num matching?
{
short vref; // volume reference number
Boolean needsUpdate; // dummy flag for this usage
// Certain attributes of an alias record are matched against the data in a
// cpb. If either the file number matches(on the same volume) or
// (creation date, type, creator)
// matches identically, a TRUE answer is returned. Otherwise, return FALSE.
if ( (!(cpb->hFileInfo.ioFlAttrib & kDirMask)) && // cpb says it is a file
(aptr->thisAliasKind == kFileAlias)) { // alias record says it is a file
if (matchFileNum && cpb->hFileInfo.ioDirID == aptr->fileNum) { // Does file number match?
if (AL_findVolume (aptr, 0 /* no autoMount */, &vref, &needsUpdate, NULL) == noErr
&& cpb->hFileInfo.ioVRefNum == vref) // Is it on the same volume
return (TRUE);
} else {
if ((aptr->fileCrDate == AL_fixedCreationDate(nil, cpb->hFileInfo.ioVRefNum, cpb->hFileInfo.ioFlCrDat)) && // How about creation date and
(cpb->hFileInfo.ioFlFndrInfo.fdType == aptr->fileType) && // file type and
(cpb->hFileInfo.ioFlFndrInfo.fdCreator == aptr->fdCreator)) // creator name?
return (TRUE);
}
} else {
if ((cpb->hFileInfo.ioFlAttrib & kDirMask) && // found a directory
(aptr->thisAliasKind == kDirAlias) && // alias also says it is a dir
(aptr->fileCrDate == AL_fixedCreationDate(nil, cpb->hFileInfo.ioVRefNum, cpb->dirInfo.ioDrCrDat))) // only creation date meaningful
return (TRUE);
}
return (FALSE);
}
/*********************************************************************
*************** Filter a file for client's acceptance *******
*********************************************************************/
static OSErr CallClientFilter(register MatchAliasParamBlk *apb, //I MatchAlias parameter block pointer
CInfoPBPtr thisCpbPtr, //I
Boolean foundTarget, //I
Boolean *filterIt) //O
{
OSErr err = noErr; // return code
CInfoPBRec cpb; // cpb to be passed to client fileFilter proc
Boolean answerFromClient; // did client say filter it or not?
*filterIt = FALSE; // init return params
apb->quitFlag = FALSE;
if (apb->aliasFilter != NULL) { // only if there is a filter to call
if (foundTarget && (thisCpbPtr == NULL)) { // need to construct a CPB to be passed to filter
// prepare a CPBInfoRec to be passed to the client filter as a param
cpb.hFileInfo.ioFDirIndex = 0; // find the resolved match by name mode
if ((err = AL_getCatInfo (apb->vref, apb->newParentDir, apb->newTargetName, &cpb)) != noErr)
goto EXIT;
thisCpbPtr = &cpb;
}
answerFromClient = (*(apb->aliasFilter)) (thisCpbPtr, &apb->quitFlag, apb->yourDataPtr);
if (foundTarget) // do not destroy filterIt parameter when calling filter to get quitFlag
*filterIt = answerFromClient;
}
EXIT:
return (err);
} // end of routine CallClientFilter
/*********************************************************************
*************** Check for entry in Alias List **************
*********************************************************************/
static Boolean NewCandidate(short vref, //I
long dir, //I
const StringPtr nam, //I
short cnt, //I
FSSpec *list) //I
{
register short i = 0; // do loop index
register FSSpec *fptr = list; // pointer into input list
// given a FSSpec data (vref, dirID and filename) and an alias list buffer,
// The current count of the number of entries in the buffer is given as
// cnt. If a similar entry exists in the buffer, return FALSE.
// Otherwise, return TRUE.
while (++i <= cnt) { // is there a similar entry in the buffer?
if (fptr->vRefNum == vref && fptr->parID == dir &&
FSEqualString(fptr->name, nam)) {
return(FALSE);
}
++fptr;
}
return (TRUE);
} // end of routine NewCandidate
/*********************************************************************
*************** Filter a found match during fast search *********
*********************************************************************/
static Boolean FilterThisMatch(register MatchAliasParamBlk *apb, //I MatchAlias parameter block pointer
Boolean foundTarget)
{
OSErr err; // result code
CInfoPBRec cpb; // cpb
CInfoPBPtr cpbPtr = NULL; // Ptr to cpb
Boolean filterIt = TRUE; // filter this entry or not?
register AliasPtrPriv aptr; // pointer to locked AliasRecord
/* Alias to a volume is OK even if fuzzy because the definition of fuzziness means that
the creation date of the volume is different. So, if we enforce the fuzziness check for
volume aliases, they won't be found. But we still may want to do this in case of
fast search on multiple volumes is being done (FileShare case). We want even volume
aliases to be forces into extra checks of creation date.
*/
/*
If the alias being resolved is a minimal alias, do not test fuzzyness. Since for
minimal aliases, no creation date, type and creator are stored, there is no point
in checking those values for found matches.
*/
aptr = apb->aptr;
if (foundTarget && (aptr->parDirID != kVolRootDirID || apb->volumeAliasFuzzy)) {
cpb.hFileInfo.ioFDirIndex = 0; // find the resolved match by name mode
err = AL_getCatInfo(apb->vref, apb->newParentDir, apb->newTargetName, &cpb);
// if the kind (file or directory) does not match, it is wrong
if (err != noErr || (!KindMatches(&cpb, aptr)))
return (TRUE);
// for fuzzy volumes, make sure creation date and type and creator match for files
// and only creation date for folders. (test not valid for minimal aliases)
if (aptr->fileNum != kInvalidValue && apb->isVolumeFuzzy) {
if (!AttributesMatch(aptr, &cpb, (!kMatchFileNumber)))
return(TRUE);
}
cpbPtr = &cpb;
} // kind matching and fuzzy volume checking done
/* If the found entry is a new candidate for the returned alias list, proceed.
Otherwise, this entry has already been filtered.
*/
if (!foundTarget || NewCandidate(apb->vref, apb->newParentDir, apb->newTargetName, apb->curCnt, apb->aliasList))
(void) CallClientFilter (apb, cpbPtr, foundTarget, &filterIt); // filter it by calling client
return (filterIt);
} // end of FilterThisMatch routine
/*********************************************************************
*************** update file number for a given new file **********
*********************************************************************/
static void UpdateFileNumber (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
(void) AL_findByName (apb->vref, apb->newParentDir, apb->newTargetName,
&apb->newFileNum, &apb->newParentDir); // update the fileNumber
} // end of UpdateFileNumber routine
/*********************************************************************
*************** Add Candidate to Alias List *****************
*********************************************************************/
static void AddCandidate(short vref, //I
long dir, //I
const StringPtr nam, //I
short *cnt, //I/O
short lim, //I
FSSpec *list) //I/O
{
register FSSpec *fptr = list; // pointer into input list
register short lcnt = *cnt; // local count
// given a FSSpec data (vref, dirID and filename) and an alias list buffer,
// add the FSSpec data to the alias list buffer. The buffer bound is given as
// lim and the current count of the number of entries in the buffer is given as
// cnt. If the buffer is not full, enter the entry into the alias list buffer.
if (lcnt < lim) { // buffer is not full
fptr = &list[lcnt];
fptr->vRefNum = vref;
fptr->parID = dir;
AL_copyPString (nam, fptr->name);
*cnt = (++lcnt);
}
} // end of routine AddCandidate
/*********************************************************************
*************** update alias list and needsUpdate flag **********
*********************************************************************/
static void UpdateAliasListAndFlag (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
register AliasPtrPriv aptr; // pointer to locked AliasRecord
aptr = apb->aptr;
// a match is found and filtered, now update the return list
AddCandidate (apb->vref, apb->newParentDir, apb->newTargetName,
&apb->curCnt, apb->aliasCount, apb->aliasList);
if (apb->needsUpdate == FALSE) { // update "needsUpdate" only if not already updated
if (apb->newParentDir != aptr->parDirID || // parent directory ID changed
// file number (or directory ID) changed
(apb->newFileNum != aptr->fileNum) ||
(! FSEqualString(apb->newTargetName, aptr->fileName))) // name changed
apb->needsUpdate = TRUE;
}
} // end of UpdateAliasListAndFlag routine
/*********************************************************************
*************** Find the target and update alias param blk ******
*********************************************************************/
static OSErr FindTarget(MatchAliasSearchKind searchKind, //I type of search
MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
OSErr err; // result code
Boolean shouldFilter=TRUE; // should filter the match ot not?
CInfoPBRec cpb; // catalog parameter block
register AliasPtrPriv aptr; // pointer to locked AliasRecord
aptr = apb->aptr;
apb->newParentDir = aptr->parDirID; // assume that it will be found at the old place
apb->newFileNum = aptr->fileNum;
AL_copyPString (aptr->fileName, apb->newTargetName);
switch (searchKind) {
case kFindByID:
// redundant check to speed up and not call FilterThisMatch
shouldFilter = (apb->isVolumeFuzzy || apb->aliasFilter != NULL);
err = AL_findByID (apb->vref, aptr, &apb->newParentDir, apb->newTargetName);
if (err != noErr) return (err);
break;
case kFindByName:
cpb.hFileInfo.ioFDirIndex = 0; // find the resolved match by name mode
err = aptr->parDirID != kInvalidValue ? // force an absolute search with dirNFErr
AL_getCatInfo(apb->vref, aptr->parDirID, aptr->fileName, &cpb) : dirNFErr;
if (err != noErr) return (err);
apb->newFileNum = cpb.hFileInfo.ioDirID;
// redundant check to speed up and not call FilterThisMatch
shouldFilter = (apb->isVolumeFuzzy || apb->aliasFilter != NULL || (!KindMatches(&cpb, aptr)));
// Did file number change? (backup and restore at same place)
apb->foundByName = TRUE;
break;
case kFindByNum:
err = AL_findFileByNum (apb->vref, aptr->parDirID, aptr->fileNum, apb->newTargetName);
if (err != noErr) return (err);
if (apb->foundByName && apb->aliasCount == 1)
--apb->curCnt; // overwrite the one that was found by name
break;
case kFindByAbsPath:
// search by absolute path
err = AL_findByAbsPath (apb->vref, aptr, &apb->newParentDir, apb->newTargetName);
if (err != noErr) { // trace dirs upto root. may be restored at a different place
if (aptr->volumeType != kInvalidValue)
err = AL_findByAbsPathToRoot (apb->vref, aptr, &apb->newParentDir, apb->newTargetName);
else // any other volume by same name has the same abs path file?
err = AL_findByAbsPathOnOtherVolume (&apb->vref, aptr, &apb->newParentDir, apb->newTargetName);
}
/* All these routines return a hint in "apb->newParentDir" so that we can set
the "hintParentDirAbs" variable correctly.
*/
if (err == fnfErr || err == noErr)
apb->hintParentDirAbs = apb->newParentDir;
if (err != noErr) return (err);
UpdateFileNumber (apb);
break;
case kFindByRelPath:
if (apb->fromFile == NULL || aptr->nlvlFrom == kNoRelativePath)
return (fnfErr);
err = AL_findByRelPath (apb->fromFile, aptr, &apb->newParentDir, &apb->newFileNum);
if (err == noErr || err == fnfErr) // found it by relative path OR a hint was returned
apb->hintParentDirRel = apb->newParentDir;
if (err == noErr) { // found it by relative path
apb->isVolumeFuzzy = FALSE; // make volume info irrelevant
apb->vref = apb->fromFile->vRefNum;
} else
return (err);
break;
default:
return (fnfErr);
} // end of switch (searchKind)
if ((!shouldFilter && NewCandidate(apb->vref, apb->newParentDir, apb->newTargetName, apb->curCnt, apb->aliasList))
|| (!FilterThisMatch(apb, kFoundTarget)))
UpdateAliasListAndFlag (apb);
return (noErr);
} // end of FindTarget routine
/*********************************************************************
******* Compute and store a hint for target that was not found ***
*********************************************************************/
static OSErr StoreHint (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
OSErr err = dirNFErr; // result code
short hintVref; // if not found, return a VRef hint of where it could have been found
long hintParentDir = kInvalidValue; // if not found, return a parent dirID hint of where it could have been found
long dummyDir; // dummy place holder
/* Return the hint of last place where the target used to be.
Make sure the directory where target should have been found is a valid directory.
*/
if (apb->rulesMask & kARMSearchRelFirst) { // Stored hint should be for relative or absolute path?
hintVref = apb->fromFile->vRefNum;
hintParentDir = apb->hintParentDirRel;
}
if (hintParentDir == kInvalidValue && // If didn't find by relative and direct search is in rule OR no relative in rules
(apb->rulesMask & (kARMSearch | kARMSearchMore))) {
hintVref = apb->vref;
hintParentDir = apb->hintParentDirAbs;
}
if (hintParentDir != kInvalidValue) { // either relative or direct search had valid values for hints
if (hintVref == 0)
err = nsvErr;
else {
if (AL_findDirByID (hintVref, hintParentDir, &dummyDir, NULL) == noErr &&
(Length(apb->aptr->fileName) > 0)) { // make sure it exists
err = noErr;
AddCandidate (hintVref, hintParentDir, apb->aptr->fileName,
&apb->curCnt, 1, apb->aliasList);
}
}
}
return (err);
} // end of StoreHint routine
/*********************************************************************
*************** Find file by attributes, recursively **********
*********************************************************************/
static OSErr FindNextByAttribute (register MatchAliasParamBlk *apb, //I MatchAlias parameter block pointer
Boolean *foundIt) //O found a match or not
{
register OSErr err; // result code
CInfoPBRec cpb; // cpb
Str63 localName; // ioNamePtr for CPB
*foundIt = FALSE; // assume that won't find the match
cpb.hFileInfo.ioFDirIndex = apb->curIoFDirIndex;
/* Given a directory, search it in order to find a file/directory that match
certain attributes. For files, they are file number or (creation date, type and
creator). For directories, it is the creation date of the directory.
*/
++cpb.hFileInfo.ioFDirIndex;// next file in the directory
// no more files or a fatal error or found it
err = AL_getCatInfo (apb->vref, apb->curDir, localName, &cpb);// get next file
if (err == noErr) {
if (AttributesMatch(apb->aptr, &cpb, kMatchFileNumber)) { // Is it a good match?
apb->newParentDir = cpb.hFileInfo.ioFlParID;
AL_copyPString(localName, apb->newTargetName);
apb->newFileNum = cpb.hFileInfo.ioDirID;
*foundIt = TRUE; // found a match
}
if (cpb.hFileInfo.ioFlAttrib & kDirMask) { // found a directory
if (apb->curIdx >= (kMaxDirStack-1)) { // ran out of directory stack
err = memFullErr; // out of memory
goto EXIT;
}else // add it to directory stack in order to search it later
(*(apb->dirStack))[apb->curIdx++] = cpb.dirInfo.ioDrDirID;
}
} // end of noErr
else if (apb->curIdx > 0) { // any more directories remaining to be searched?
apb->curDir = (*(apb->dirStack))[--apb->curIdx]; // next directory from stack
cpb.hFileInfo.ioFDirIndex = 0; // start search at the beginning
err = noErr;
}
apb->curIoFDirIndex = cpb.hFileInfo.ioFDirIndex;
EXIT:
return (err);
} // end of FindNextByAttribute routine
/*********************************************************************
*************** Find file(s) or directory(s) by CatSearch ******
*********************************************************************/
static OSErr FindNextByCatSrch(register MatchAliasParamBlk *apb, //I MatchAlias parameter block pointer
Boolean *foundIt) //O found a match or not
{
OSErr err; // result code
CSParam cspb; // CatSearch parameter block
CInfoPBRec cpb1, cpb2; // CatSearch setup catlog param blocks
FSSpec ans; // CatSearch return entry
register AliasPtrPriv aptr; // alias record pointer
unsigned long fixedCrDate; // fixed creation date for AppleShare
*foundIt = FALSE; // assume that won't find the match
aptr = apb->aptr;
// set up CatSearch parameter block
cspb.ioNamePtr = cspb.ioOptBuffer = NULL;
cspb.ioVRefNum = apb->vref;
cspb.ioMatchPtr = &ans;
cspb.ioReqMatchCount = 1;
cspb.ioSearchBits = fsSBFlAttrib + fsSBFlFndrInfo + fsSBFlCrDat;
if (aptr->thisAliasKind == kDirAlias)
// for files, type and creator are important but for folders they are not
cspb.ioSearchBits -= fsSBFlFndrInfo;
cspb.ioSearchInfo1 = &cpb1;
cspb.ioSearchInfo2 = &cpb2;
cspb.ioSearchTime = KMaxCSrchTimeOut; // length of time to run search
// later on, may want to refine it depending upon performance
cspb.ioCatPosition = apb->prec; // input CatSearch position record
cpb1.hFileInfo.ioNamePtr = NULL; // name was not important
cpb2.hFileInfo.ioNamePtr = NULL;
cpb1.hFileInfo.ioFlAttrib = (aptr->thisAliasKind == kDirAlias) ? kDirMask : 0;
cpb2.hFileInfo.ioFlAttrib = kDirMask;// only bit 4 is important
fixedCrDate = AL_fixedCreationDate(nil, apb->vref, aptr->fileCrDate);
cpb1.hFileInfo.ioFlCrDat = cpb2.hFileInfo.ioFlCrDat =
aptr->fileCrDate + (aptr->fileCrDate - fixedCrDate);
if (cspb.ioSearchBits & fsSBFlFndrInfo) {
// for files, type and creator are important
cpb1.hFileInfo.ioFlFndrInfo.fdType = aptr->fileType;;
cpb1.hFileInfo.ioFlFndrInfo.fdCreator = aptr->fdCreator;
// create the mask bits so that only type and creator are important.
cpb2.hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
cpb2.hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
cpb2.hFileInfo.ioFlFndrInfo.fdFlags = 0;
cpb2.hFileInfo.ioFlFndrInfo.fdLocation.h = 0;
cpb2.hFileInfo.ioFlFndrInfo.fdLocation.v = 0;
cpb2.hFileInfo.ioFlFndrInfo.fdFldr = 0;
}
err = PBCatSearch (&cspb, false);
if (err == noErr || err == eofErr) { //if reached end of volume, it is ok
if (cspb.ioActMatchCount == 1) {
apb->newParentDir = ans.parID;
AL_copyPString(ans.name, apb->newTargetName);
UpdateFileNumber (apb);
*foundIt = TRUE; // found a match
}
if (err == noErr) // new position not meaningful for eofErr or fnfErr
apb->prec = cspb.ioCatPosition; // return the new position
} else
apb->CatSearchAvailable = FALSE;
return (err);
} // end of FindNextByCatSrch routine
/*********************************************************************
*************** search a volume for an alias match **************
*********************************************************************/
static void SearchOneVolume (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
OSErr err; // result code
Boolean foundIt=FALSE; // found the next match by slow search or not?
unsigned long startCount; // remember ticks when volume search starts
unsigned long currentCount; // value of current ticks
if (apb->quitFlag || apb->aptr->fileNum == kInvalidValue) // no valid data to match against
return;
apb->prec.initialize = 0; // from beginning of volume
apb->CatSearchAvailable = TRUE; // assume it is available
apb->curDir = kRootDirID; // current directory that we are searching, start at root
apb->curIdx = 0; // current index into directory stack
apb->curIoFDirIndex = 0; // current index into the directory being searched
apb->dirStack = NULL;
startCount = TickCount(); // remember when volume search started
do {
if (apb->aptr->parDirID != kVolRootDirID) { // not a volume alias, file/directory alias
if (apb->CatSearchAvailable)
err = FindNextByCatSrch (apb, &foundIt);
// FindNextByCatSrch will set apb->CatSearchAvailable & hence the check and not else
if (!apb->CatSearchAvailable) {
if (apb->dirStack == NULL) {
apb->dirStack = (LongsHandle)(NewHandle(sizeof(long)*kMaxDirStack));
if (apb->dirStack == NULL) // can't do the search
return;
}
err = FindNextByAttribute (apb, &foundIt);
}
} else { // handle volume aliases specially since CatSearch and recursive index search can't handle them
HVolumeParam vpb; // volume parameter block
vpb.ioNamePtr = apb->newTargetName;
vpb.ioVolIndex = 0; // find by vRefNum mode
vpb.ioVRefNum = apb->vref; // put the vref in
if (PBHGetVInfo ((HParmBlkPtr)&vpb, FALSE) == noErr &&
apb->aptr->volumeCrDate == AL_fixedCreationDate(&vpb, vpb.ioVRefNum, vpb.ioVCrDate)) { // found a match
apb->newParentDir = apb->aptr->parDirID;
apb->newFileNum = apb->aptr->fileNum;
foundIt = TRUE;
}
err = fnfErr; // force a quit from the while loop
}
currentCount = TickCount();
if (foundIt || (currentCount >= (startCount + kCancelWait))) {
if (!FilterThisMatch (apb, foundIt) && foundIt)
UpdateAliasListAndFlag (apb);
startCount = TickCount(); // restart the count
}
} while (apb->curCnt < apb->aliasCount && (! apb->quitFlag) && err == noErr);
if (apb->dirStack != NULL) // dispose directory stack
DisposHandle ((Handle)apb->dirStack);
} // end of SearchOneVolume routine
/*********************************************************************
*************** search all mounted volumes for an alias match **
*********************************************************************/
static void SearchAllVolumes(Boolean vrefSrchFlg, //I passed vref is already searched, ignore it
short vref, //I volume reference number/WD ref
register MatchAliasParamBlk *apb, //I MatchAlias parameter block pointer
unsigned long rulesMask, //I search rules mask , fast or slow or both?
MatchAliasSearchKind fastSearchKind) //I what kind of fast search?
{
register VCB *vcbPtr; // VCB pointer
vcbPtr = (VCB *)GetVCBQHdr()->qHead;
while (vcbPtr != NULL) {
if ((vrefSrchFlg != kDontSrchVref) || (vref != vcbPtr->vcbVRefNum)) {
// ignore the passed vref if the flag says so, it is already searched
apb->vref = vcbPtr->vcbVRefNum;
if (rulesMask & kARMSearch)
(void) FindTarget (fastSearchKind, apb);
if (rulesMask & kARMSearchMore) // do slow search by CatSearch
SearchOneVolume (apb);
if (apb->curCnt >= apb->aliasCount || apb->quitFlag) // filled the buffer
break;
}
vcbPtr = (VCB *) vcbPtr->qLink;
}
} // end of SearchAllVolumes routine
/*********************************************************************
*************** Are we trying to mount ourself? ******************
*********************************************************************/
Boolean AL_isItSelf (register AliasPtrPriv aptr, // pointer to locked AliasRecord
Boolean *needsUpdate) // Does the alias record need updating?
{
Str32 zoneName; // my zone name
Str31 serverName; // my server name
Boolean IsCurrentZoneStar; // Is current zone a '*'?
Boolean IsAliasZoneStar; // Is zone in alias record a '*'?
char *zoneNamePtr; // pointer to zone name from alias record
AL_GetMyZonePhs2(zoneName);
AL_GetMyServer(serverName);
/* If alias record or current zone says local zone, assume zone already matches.
But tell the client to update the record to get real zone if possible. */
IsCurrentZoneStar = Length(zoneName) == 1 && zoneName[1] == '*';
zoneNamePtr = AL_getAFPinfo (aptr, asiZoneName);
IsAliasZoneStar = Length(zoneNamePtr) == 1 && ((*(zoneNamePtr+1)) == '*');
if (IsAliasZoneStar && (!IsCurrentZoneStar)) // force the update of alias record to get real zone name
*needsUpdate = TRUE;
return ((IsCurrentZoneStar || IsAliasZoneStar || FSEqualString(zoneName, zoneNamePtr))
&& FSEqualString(serverName, AL_getAFPinfo (aptr, asiServerName)));
} // end of AL_isItSelf routine
/*********************************************************************
*************** Get Next Shared Folder ***************************
*********************************************************************/
static OSErr GetNextSharedFolder (short index, //I index for the folder to be got
CInfoPBPtr cpbPtr) // catalog parameter block pointer
{
OSErr err; // result code
ParamBlockRec sharedFolderInfo;
HVolumeParam vpb; // volume parameter block
sharedFolderInfo.cntrlParam.ioNamePtr = NULL;
sharedFolderInfo.cntrlParam.csCode = SCGetExpFldr;
sharedFolderInfo.cntrlParam.csParam[0] = index;
err = GetExportedFolderInfo(&sharedFolderInfo, FALSE);
if (err == noErr) {
cpbPtr->hFileInfo.ioFDirIndex = -1; // interested in directory info only
err = AL_getCatInfo (sharedFolderInfo.cntrlParam.ioVRefNum,
*((long *)&sharedFolderInfo.cntrlParam.csParam[1]),
cpbPtr->hFileInfo.ioNamePtr, cpbPtr);
if (err == noErr && cpbPtr->hFileInfo.ioFlParID == kVolRootDirID) {
/* Return the volume creation date in the cpb and not the root dir's creation date
for the entire volume itself as the SharePoint. File System treats them both differently.
*/
if (AL_findVolByName (cpbPtr->hFileInfo.ioNamePtr, &vpb) == noErr)
cpbPtr->hFileInfo.ioFlCrDat = vpb.ioVCrDate;
}
}
return (err);
} // end of GetNextSharedFolder routine
/*********************************************************************
*************** Switch alias record to auxiliary info ************
*********************************************************************/
static void SwitchToAux (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
register AuxAliasInfo *apbAuxPtr; // pointer to locked AliasRecord
register AliasPtrPriv aptr; // pointer to locked AliasRecord
char *aliasAuxPtr; // auxiliary info pointer in alias record
short aliasAuxLen; // length of auxiliary alias record
aptr = apb->aptr;
apbAuxPtr = &apb->auxAliasRecord;
AL_copyPString (aptr->volumeName, apbAuxPtr->auxVolName);
apbAuxPtr->auxVolCrDate = aptr->volumeCrDate;
apbAuxPtr->auxVolType = aptr->volumeType;
apbAuxPtr->auxDirIDs.auxParDirID = aptr->parDirID;
apbAuxPtr->auxDirIDs.auxFileNum = aptr->fileNum;
aliasAuxPtr = AL_getVarPtr(aptr, kAuxRemoteAlias, &aliasAuxLen);
AL_changeToAuxInfo (aptr, (AuxAliasInfo *)aliasAuxPtr);
apb->hintParentDirAbs = aptr->parDirID;
apb->auxAliasSwitch = TRUE;
} // end of SwitchToAux routine
/*********************************************************************
*************** Do fast search on multiple volumes ***************
*********************************************************************/
static void FastSearchAllVolumes (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
register AliasPtrPriv aptr; // pointer to locked AliasRecord
short prevCnt; // remember current count of found candidates
if (apb->rulesMask & kARMSearch) { // Does rulesMask allow fast search?
aptr = apb->aptr;
apb->isVolumeFuzzy = TRUE; // the found volume would be fuzzy, force extra checks
apb->volumeAliasFuzzy = TRUE; // force extra checks for volume aliases themselves
prevCnt = apb->curCnt;
/* Fast search on multiple volumes mean looking for it first by ID and then by name
in parent directory. Also, caller controls whether extra checks are done or not
by setting the isVolumeFuzzy and volumeAliasFuzzy flags of MatchAlias parameter block.
*/
SearchAllVolumes ((!kDontSrchVref), apb->vref, apb, kARMSearch, kFindByID);
if (apb->curCnt < apb->aliasCount && (!apb->quitFlag))
SearchAllVolumes ((!kDontSrchVref), apb->vref, apb, kARMSearch, kFindByName);
if (prevCnt != apb->curCnt)
apb->needsUpdate = TRUE;
apb->searchedAllVols = TRUE;
}
} // end of FastSearchAllVolumes routine
/*********************************************************************
*************** Handle a shared volume (FileShare like) **********
*********************************************************************/
static OSErr HandleSharedVolume (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
OSErr resultErr=noErr; // result code
OSErr err; // result code
register AliasPtrPriv aptr; // pointer to locked AliasRecord
CInfoPBRec cpb; // catalog parameter block
Str27 localName; // temporary local volume name
register short index = 0; // index through all shared folders
short auxLen; // length of auxiliary real parent dirID
AuxAliasDirIDs *realDirPtr; // pointer to real directory ID info
aptr = apb->aptr;
if (AL_isItSelf(aptr, &apb->needsUpdate)) { // on the server side
if (aptr->volumeAttributes & kAuxRealDirID && aptr->volumeType == kVolForeign) {
// on server and accessing remote alias
/* Get info about all currently shared folders and see if any of them is the
correct target. If could not identify the target volume, the only thing we can
do is quick search on multiple volumes for the target.
*/
apb->auxAliasRecord.auxDirIDs.auxParDirID = aptr->parDirID;
apb->auxAliasRecord.auxDirIDs.auxFileNum = aptr->fileNum;
realDirPtr = (AuxAliasDirIDs *) AL_getVarPtr(aptr, kAuxRealDirID, &auxLen);
aptr->parDirID = realDirPtr->auxParDirID;
aptr->fileNum = realDirPtr->auxFileNum;
apb->auxRealDirSwitch = TRUE;
do {
cpb.hFileInfo.ioNamePtr = localName;
err = GetNextSharedFolder(++index, &cpb);
if (err == noErr) {
if (FSEqualString (localName, aptr->volumeName) &&
cpb.hFileInfo.ioFlCrDat == aptr->volumeCrDate) {
apb->vref = cpb.hFileInfo.ioVRefNum;
apb->needsUpdate = TRUE;
break;
}
}
} while (err == noErr);
/* FileShare is not running or can't locate the correct volume.
Force a search on all mounted volumes as the last recourse.
*/
if (err != noErr) {
FastSearchAllVolumes(apb);
/* Already did fast search on all mounted volumes on the server locally.
No more volumes to search or mount, so get out.
*/
resultErr = nsvErr;
}
}
} else { // we are on remote machine (at least we think so)
// on client workstation using alias created on server
if (aptr->volumeAttributes & kVolAuxRemoteInfo && aptr->volumeType != kVolForeign) {
SwitchToAux (apb); // Is the shared folder itself mounted?
if (AL_checkIfMounted(aptr, &apb->vref, &apb->needsUpdate) != noErr) {
AL_changeToAuxInfo (aptr, &apb->auxAliasRecord);
apb->hintParentDirAbs = aptr->parDirID;
if (AL_checkIfMounted(aptr, &apb->vref, &apb->needsUpdate) != noErr) { // Is the entire volume mounted?
SwitchToAux (apb); // back to primary search info in this case
if ((apb->rulesMask & kARMMountVol) && (aptr->volumeType != kInvalidValue) &&
(aptr->volumeAttributes & kVolMntExists))
resultErr = AL_mountForeign(aptr, &apb->vref, &apb->needsUpdate,
apb->rulesMask & kARMNoUI ? kNoUserInterface : kUserInterface, &apb->auxAliasRecord);
}
}
}
}
return (resultErr);
} // end of HandleSharedVolume routine
/*********************************************************************
*************** Post processing of returned needsUpdate flag **
*********************************************************************/
static void PostProcessNeedsUpdateFlag (register MatchAliasParamBlk *apb) //I MatchAlias parameter block pointer
{
if (apb->curCnt > 1) // if returned multiple answers, set the flag.
apb->needsUpdate = TRUE;
/* If relative has first priority, but found by absolute, set needsUpdate flag. */
if ((!apb->needsUpdate) && apb->curCnt > 0)
{
if ((apb->aptr->nlvlFrom != kNoRelativePath) &&
(apb->rulesMask & kARMSearchRelFirst) &&
(apb->rulesMask & kARMSearch) &&
(!apb->foundByRelativeFirst) &&
(apb->fromFile->vRefNum == apb->aliasList[0].vRefNum))
apb->needsUpdate = TRUE;
}
if (apb->aptr->fileNum == kInvalidValue) // never force update of minimal aliases
apb->needsUpdate = FALSE;
} // end of PostProcessNeedsUpdateFlag routine
/**********************************************************************
*************** Match an alias *******************************
*********************************************************************/
pascal OSErr AL_matchAlias(const FSSpec *fromFile, //I aliased from file
unsigned long rulesMask, //I search rules mask
const AliasHandlePriv alias, //I alias record handle
short *aliasCount, //I/O # of entries in alias list
FSSpecPtr aliasList, //I/O alias list buffer
Boolean *needsUpdate, //O does alias needs updating?
AliasFilterProcPtr aliasFilter, //I filter proc for alias match
Ptr yourDataPtr) //I a callback param passed to filter proc
{
OSErr err; // result code
HVolumeParam vpb; // volume parameter block
char masterFlags; // flags to remember before locking and unlocking handles
MatchAliasParamBlk apb; // parmater block for passing to internal routines
register AliasPtrPriv aptr; // pointer to locked AliasRecord
short prevCnt; // remember current count of found candidates
short prevVref; // remember vRefNum before multiple volume search
unsigned long searchBits; // search rules bits from rulesMask
short prevSlowSearchedVref = 0; // remember the volume that was already slow searched if any
apb.needsUpdate = FALSE; // assume update not needed
/* Validate the input parameters. */
searchBits = (rulesMask & (kARMSearch | kARMSearchMore | kARMSearchRelFirst));
if (aliasList == NULL || // can't allow null answer buffer
*aliasCount < 1 || // can't ask for 0 or negative matches
searchBits == 0 || // have to specify at least one search strategy
(fromFile == NULL && searchBits == kARMSearchRelFirst) || // No fromFile but only relative search specified
(AL_validateHandle(alias) != noErr)) { // Is it a handle to invalid alias record?
return (paramErr);
}
/* Lock the alias handle and remember the alias record pointer. */
masterFlags = HGetState ((Handle)alias); // remember master flags
HLock((Handle)alias); // lock the passed alias record
aptr = apb.aptr = *alias; // get alias record pointer
/* set up the MatchAlias parameter block. */
apb.fromFile = fromFile;
apb.rulesMask = rulesMask;
apb.aliasCount = *aliasCount;
apb.aliasList = aliasList;
apb.aliasFilter = aliasFilter;
apb.yourDataPtr = yourDataPtr;
apb.curCnt = 0;
apb.quitFlag = FALSE;
apb.isVolumeFuzzy = FALSE;
apb.foundByName = FALSE;
apb.foundByRelativeFirst = FALSE;
apb.hintParentDirAbs = aptr->parDirID;
apb.hintParentDirRel = kInvalidValue;
apb.vref = 0;
apb.auxAliasSwitch = FALSE;
apb.auxRealDirSwitch = FALSE;
apb.searchedAllVols = FALSE;
apb.volumeAliasFuzzy = FALSE;
/* if relative search first specified, give it priority over absolute search. */
if (apb.rulesMask & kARMSearchRelFirst) {
err = FindTarget (kFindByRelPath, &apb);
if (err == noErr && apb.curCnt != 0) {
apb.foundByRelativeFirst = TRUE;
// for return buffer yet not full, continue search by falling through
mExitIfQuitOrBufFull(apb.quitFlag, apb.curCnt, *aliasCount); // if buffer full or client quit , exit
}
/* Optimization for no other than relative search requested. */
if (searchBits == kARMSearchRelFirst)
goto EXIT;
apb.vref = 0; // force an auto mount and volume search since we are not done yet!
}
/* Handle the FileShare cases here. For such volumes,
the actual information is stored in the auxiliary area. Hence, it is crucial to
set up the alias record data correctly before we start processing the alias record.
*/
if (AL_isAFPmedia(aptr) &&
(aptr->volumeAttributes & kVolAuxRemoteInfo || aptr->volumeAttributes & kAuxRealDirID)) {
err = HandleSharedVolume(&apb);
if (err != noErr) goto EXIT;
}
/* Locate the target volume. */
if (apb.vref == 0) {
/* was not a shared volume or correct volume is not located yet. */
err = AL_findVolume (aptr, apb.rulesMask, &apb.vref, &apb.needsUpdate,
apb.auxAliasSwitch ? (&apb.auxAliasRecord) : NULL);
if (err != noErr) goto EXIT;
}
/* There is a concept of a fuzzy volume. If the found volume's creation date does
not match, it is possible that it is the wrong volume. In this case, we set the
fuzzy flag. This allows later on alias matching to be more restrictive.
Also, AppleShare foreign volumes are not counted as fuzzy evenif the creation date
is different (since zone and server and volume names matched, it is OK.
*/
if (apb.needsUpdate && (!AL_isAFPmedia(aptr))) {
/* means that found the volume but something about the volume has changed */
err = AL_findVolByVRefNum (apb.vref, &vpb); // make sure volume is still mounted
if (err != noErr) goto EXIT;
if (vpb.ioVCrDate != aptr->volumeCrDate)
apb.isVolumeFuzzy = TRUE; // the found volume is fuzzy
}
/* Now do the search for target itself. */
if (apb.rulesMask & kARMSearch) { // if quick search specified
// Find file by fileID or directory by dirID
err = FindTarget (kFindByID, &apb);
if (err == noErr) {
// for return buffer yet not full, continue search by falling through
mExitIfQuitOrBufFull(apb.quitFlag, apb.curCnt, *aliasCount); // if buffer full or client quit , exit
}
// try finding by name in the parent directory
err = FindTarget (kFindByName, &apb);
switch (err) {
case noErr:
/* Found by name in the same parent directory and fileNumber is the same.
No need to look further by absolute path search or fileNumber search
evenif multiple matches requested.
*/
if (apb.newFileNum == aptr->fileNum || aptr->fileNum == kInvalidValue
|| aptr->thisAliasKind == kDirAlias)
break;
// If found by name but file number does not match, continue
// search by file number as a renamed file. But remember the fact
// that a match by name was found.
if (apb.quitFlag) goto EXIT;
apb.foundByName = TRUE;
case fnfErr:
if (aptr->thisAliasKind == kFileAlias) {
// how about in parent directory as a renamed file?
err = FindTarget (kFindByNum, &apb);
if (err == noErr) {
mExitIfQuitOrBufFull(apb.quitFlag, apb.curCnt, *aliasCount); // if buffer full or client quit , exit
}
}
// fall through for files and directories to find them by absolute path
case dirNFErr: // may be backed up and restored. dirIDs will be different.
// search by absolute path
err = FindTarget (kFindByAbsPath, &apb);
if (err == noErr) { // found it, return the result
mExitIfQuitOrBufFull(apb.quitFlag, apb.curCnt, *aliasCount); // if buffer full or client quit , exit
}
break;
default:
break;
} // end of switch of finding by name
} // end of quick search for a file or a directory
/* search further using slow search. */
if (apb.rulesMask & kARMSearchMore) {
prevSlowSearchedVref = apb.vref;
SearchOneVolume (&apb);
}
EXIT:
/* Do the post processing and set up return parameters correctly.
No need for relative or multiple volume search if user canceled out of
the entire operation.
*/
/* if relative search requested, do it now. Do it only if buffer is not full
and the previous client filtering did not tell us to quit. Also, if the
relative search had priority over absolute search, it was already done.
*/
if ((apb.curCnt < *aliasCount) && (!apb.quitFlag) &&
(err != userCanceledErr) && (!(apb.rulesMask & kARMSearchRelFirst))) {
/* Do not override nsvErr. If kARMSearchRelFirst bit was set, that was already done.
But it is not set and absolute search had priority. In such a case, if we can't
find by relative search, return whatever error was last set during abs search.
*/
prevCnt = apb.curCnt;
(void) FindTarget (kFindByRelPath, &apb); // no error checking here
if (prevCnt != apb.curCnt)
apb.needsUpdate = TRUE; // did not find absolute, but found relative
} // end of fast relative search
#ifdef FORCE_MULTIPLEVOL_SEARCH
/* Also, if we have not located or auto mounted the correct target volume and if a fast search
was not already done on all mounted volumes (i.e. FileShare case via HandleSharedVolume) we
can do it here by pretending that the kARMMultVols bit was set in rulesMask. This could
detect aliases in case when aliases were created while FileShare was not running and then
any of parent folders were shared later on.
*/
if (err == nsvErr && (!apb.searchedAllVols) && (apb.rulesMask & kARMMountVol))
apb.rulesMask |= kARMMultVols;
#endif FORCE_MULTIPLEVOL_SEARCH
/* If the multiple volume search bit is set, now is the time to do it.
Do it only if the input buffer is not full and quitFlag is not set.
For minimal alases, no CatSearch for creation date, type
and creator since these are invalid values.
*/
if ((apb.curCnt < *aliasCount) && (!apb.quitFlag) &&
(err != userCanceledErr) && (aptr->fileNum != kInvalidValue)) {
if (apb.rulesMask & kARMMultVols) {
prevCnt = apb.curCnt;
prevVref = apb.vref; // volume on which the original target was searched
FastSearchAllVolumes (&apb);
if ((apb.rulesMask & kARMSearchMore) && (apb.curCnt < *aliasCount) && (!apb.quitFlag) )
SearchAllVolumes ((prevSlowSearchedVref != 0) ? kDontSrchVref : (!kDontSrchVref),
prevSlowSearchedVref, &apb, kARMSearchMore, kFindByNum /* this is ignored. */);
if (prevCnt != apb.curCnt) // found on a different volume
apb.needsUpdate = TRUE;
apb.vref = prevVref; // restore original target volume
}
}
/* Set the returned needsUpdate flag correctly. */
PostProcessNeedsUpdateFlag (&apb);
/* Set the return error . */
if (apb.curCnt)
err = noErr; // if at least one match returned, no error
else if (err == noErr || err == fnfErr || // target not found, zero match during search
(apb.vref != 0 && err == afpAccessDenied)) {
/* return the hint of last place where the target used to be. In such a case,
error returned is still fnfErr. The returned count is one if the directory
where target should have been found is a valid directory.
*/
err = StoreHint(&apb);
/* Eventhough count returned is one, returned answer is not valid.
It is just a hint as to where the target used to be.
*/
if (err == noErr) {
err = fnfErr;
apb.needsUpdate = FALSE; // for hints, needsUpdate flag has to be false
}
}
/* for shared volumes on client side, we had changed info in the alias record.
set it back to the original.*/
if (apb.auxAliasSwitch)
AL_changeToAuxInfo(aptr, &apb.auxAliasRecord);
if (apb.auxRealDirSwitch) {
aptr->parDirID = apb.auxAliasRecord.auxDirIDs.auxParDirID;
aptr->fileNum = apb.auxAliasRecord.auxDirIDs.auxFileNum;
}
*aliasCount = apb.curCnt; // return found alias count and needsUpdate flag
*needsUpdate = apb.needsUpdate;
HUnlock((Handle)alias); // unlock the alias record
HSetState((Handle)alias, masterFlags); // restore original state
return (err);
} // end of MatchAlias routine
/*********************************************************************
*************** Canonify a file name ***********************
*********************************************************************/
pascal OSErr AL_canonifyFile ( short vRefNum, //I volume ref #/working dir
long dirID, //I directory ID
const Str255 *fileName, //I file name
FSSpec *canonicalFile) //O returned canonical form
{
#ifndef FSMakeFSSpec_FOR_MFS_WORKS
if (canonicalFile == NULL)
return (paramErr);
else
return (FSMakeFSSpec (vRefNum, dirID, (ConstStr255Param)fileName, canonicalFile));
#else
OSErr err; // result code
long tdir; // temporary directory ID
long fnum; // file number
HVolumeParam vpb; // volume parameter block
Boolean noFileName; // input filename is null or empty
Boolean isFullPath=FALSE; // input filename is fullpath or not
if (canonicalFile == NULL)
return (paramErr);
/* Try to use the file system call if it works. It does not support MFS volumes. */
if (FSMakeFSSpec (vRefNum, dirID, (ConstStr255Param)fileName, canonicalFile) == noErr)
return (noErr);
noFileName = ((fileName == NULL) || (Length(fileName) == 0));
canonicalFile->parID = dirID; // use client supplied directory ID
if (!noFileName) { // fileName parameter is valid
AL_getFilename ((unsigned char *)fileName+1, (Length(fileName) <= (sizeof(Str63)-1)) ? Length(fileName) : (sizeof(Str63)-1),
canonicalFile->name); // get the filename component
isFullPath = AL_isFullpath((unsigned char *)fileName+1, Length(fileName));
}
if (isFullPath) { // fullpath is specified in fileName parameter, decode it.
Str255 localVolumeName; // temporary local volume name
// fullpath is a special case where correct volume ref number needs to be computed
AL_getVolname ((unsigned char *)fileName+1, Length(fileName), localVolumeName); // get volume name
if ((err = AL_findVolByName (localVolumeName, &vpb)) != noErr)
goto EXIT;
canonicalFile->vRefNum = vpb.ioVRefNum; // returned vRefNum
// for full paths, start with root dirID
canonicalFile->parID = (vpb.ioVSigWord != kFlatVolume) ? kVolRootDirID : kRootDirID;
// Handle the special case for Canonify called for a volume. See if the passed
// filename is indeed a volume name.
if (FSEqualString ((Str255)fileName, (Str255)localVolumeName)) {
// special case, canonify called for a volume
canonicalFile->parID = kVolRootDirID;
*canonicalFile->name = Length(localVolumeName) -1; // do not copy separator char
BlockMove (localVolumeName+1, canonicalFile->name+1, (*canonicalFile->name));
goto EXIT; // done with special case of volume
}
} else { // not a fullpath specification
WDPBRec wdpb; // working directory parameter block
wdpb.ioVRefNum = vRefNum; // this working direcotry
wdpb.ioWDIndex = 0;
wdpb.ioWDProcID = 0;
wdpb.ioWDVRefNum = 0;
wdpb.ioNamePtr = NULL;
if ((err = PBGetWDInfo(&wdpb, FALSE)) != noErr) // info about this one
goto EXIT;
canonicalFile->vRefNum = wdpb.ioWDVRefNum; // returned vRefNum
if (dirID == 0) // override only if not specified
canonicalFile->parID = wdpb.ioWDDirID; // returned dirID
if (noFileName)
err = AL_findDirByID (canonicalFile->vRefNum, canonicalFile->parID,
&canonicalFile->parID, canonicalFile->name);
}
/* If our volume is a MFS volume, no need to compute correct parent dirID
for partial or full path names since the whole structure is flat. */
if (err == noErr) { // everything was OK so far
if (!isFullPath) {
err = AL_findVolByVRefNum(canonicalFile->vRefNum, &vpb);
if (err != noErr) goto EXIT;
}
if (vpb.ioVSigWord != kFlatVolume) {
Str255 localPartialName; // temporary local partial pathname
/*If just a leaf name was specified as the fileName parameter, we are done.
If a partial or full pathname was specified, we still need to compute the
correct parent directory ID for the file or directory name. */
if ((!noFileName) && (! FSEqualString ((Str255)fileName, canonicalFile->name))) {
AL_stripFilename ((unsigned char *)fileName+1, Length(fileName), localPartialName);
err = AL_findByName (canonicalFile->vRefNum, canonicalFile->parID,
localPartialName, &canonicalFile->parID,
&fnum);
if (err == noErr) { // the directory does exist
if (Length(canonicalFile->name) == 0) // case of name specified ending in a colon
err = AL_findDirByID (canonicalFile->vRefNum, canonicalFile->parID,
&canonicalFile->parID, canonicalFile->name); // compute its name
}
}
}
}
if (err != noErr) { // if the directory does not exist, return that error
if (err == fnfErr) //File system returns fnfErr for directory not existing in this case
err = dirNFErr;
goto EXIT;
} else {
/* return correct error if file is non-existent. If file does not exist, the
canonical form is returned correctly but fnfErr is returned as the function
result. Factor out volume case for MFS volumes because getting volume info by name
does not work for them if dirID is kVolRootDirID. */
if (vpb.ioVSigWord != kFlatVolume || canonicalFile->parID != kVolRootDirID)
err = AL_findByName (canonicalFile->vRefNum, canonicalFile->parID,
canonicalFile->name, &fnum, &tdir);
}
EXIT:
return (err);
#endif FSMakeFSSpec_FOR_MFS_WORKS
} // end of canonifyFile routine
/*********************************************************************
*************** Update an alias record ***********************
*********************************************************************/
pascal OSErr AL_updateAlias (const FSSpec *fromFile, //I aliased from file
const FSSpec *target, //I aliased to file
AliasHandlePriv alias, //I alias record handle
Boolean *wasChanged) //O did alias record change?
{
return (AL_fillAlias (fromFile, target, !kCreateAlias, alias, wasChanged, kCompleteAlias, NULL));
} // end of UpdateAlias routine
/*********************************************************************
*************** get information from an alias record **************
*********************************************************************/
pascal OSErr AL_getAliasInfo( const AliasHandlePriv alias, //I alias record handle
AliasInfoType index, //I index specifying requested information
Str63 theString) //O returned info as string
{
register AliasPtrPriv aptr; // alias record pointer
short len = 0; // variable info datalength
register short i; // for loop index
char *infoPtr; // ptr to data being returned
short nchInAPath; // # of chars in absolute path
short ndirToRoot; // # of dirs to Root for the alias
register char *s, *t; // temporary character pointers
if (index < asiZoneName || (AL_validateHandle(alias) != noErr))
return (paramErr);
aptr = *alias; // get alias record pointer
if (index == asiAliasName) // alias name
AL_copyPString(aptr->fileName, theString);
else { // not an alias name
if (index == asiVolumeName) { // volume name
len = Length(aptr->volumeName);
infoPtr = aptr->volumeName + 1;
}
else { // data comes from variable length info part
if (index >= asiParentName) { // some other parent folder name
/* Example: vol:lvl1:lvl2:afile will have ndirToRoot = 2, lvl1 and lvl2. Index of 1
will return lvl2. Index of 2 will return lvl1 and index of >= 3 will return empty string. */
infoPtr = AL_getVarPtr (aptr, kDirIDs, &ndirToRoot);
ndirToRoot = (ndirToRoot >> 2); // since dirIDs are long, this is equivalent to
// division by sizeof(long);
if (index > ndirToRoot) // return empty string
len = 0;
else { // return a parent
s = t = AL_getVarPtr (aptr, kAbsPath, &nchInAPath); // pointer to absolute path name
s += nchInAPath - 1; // point to the last character in abs path
for (i=index-1; i>=0; --i) { // locate separator char index times
// locate a separator character index times
while (*s-- != kChrSeparator && s > t)
; // do nothing
}
if (s > t) { // now locate the separator character before found name
infoPtr = s; // before the separator character
while (*infoPtr != kChrSeparator && infoPtr > t)
--infoPtr;
if (infoPtr > t) { // found the name to be returned
len = s - infoPtr;
++infoPtr; // point to the first cahracter of name
}
} // end of (s>t)
} // end of return a parent
} // some other parent folder name
else if (index == asiZoneName || index == asiServerName) { // zone name or server name
if (AL_isAFPmedia(aptr)) {
infoPtr = AL_getAFPinfo (aptr, index);
len = Length(infoPtr);
++infoPtr;
}
}
} // data comes from variable length info part
*theString = len;
if (len > 0)
BlockMove (infoPtr, theString+1, len);
} // end of not an alias name
return (noErr);
} // end of routine AL_getAliasInfo
/**********************************************************************
*************** Follow a Finder alias ***********************
*********************************************************************/
pascal OSErr AL_FollowFinderAlias(const FSSpec *fromFile, //I aliased from file
AliasHandle alias, //I/O alias record handle
Boolean logon, //I is auto logon allowed?
FSSpec *target, //O resolved alias FSSpec
Boolean *wasChanged) //O did any thing change?
{
OSErr err; // result code
short aliasCount = 1; // alias list length
unsigned long logonMask;// logon mask depending upon logon param
FSSpec fromSpec;
logonMask = logon ? kARMMountVol : 0;
fromSpec = (*fromFile);
// This is same as calling ResolveAlias except we do not want auto update of alias record so that we can
// ignore the same folder case.
err = MatchAlias(&fromSpec, kARMSearchRelFirst | kARMSearch | logonMask, alias, &aliasCount, target, wasChanged, nil, nil);
// If found target is in the same folder, ignore it. This leads to wrong targets because
// all aliases of Finder have same relative path of being in same folder initially.
if (err == noErr && fromSpec.vRefNum == target->vRefNum && fromSpec.parID == target->parID) {
aliasCount = 1;
err = MatchAlias(&fromSpec, kARMSearch | logonMask, alias, &aliasCount, target, wasChanged, nil, nil);
// If this direct search found the original fromSpec itself, return error
if (err == noErr && fromSpec.vRefNum == target->vRefNum &&
fromSpec.parID == target->parID && FSEqualString(fromSpec.name, target->name))
err = fnfErr;
}
if ((err == noErr) && *wasChanged) // MatchAlias tells us that it needs updating
err = UpdateAlias(&fromSpec, target, alias, wasChanged);
return (err);
} // end of FollowFinderAlias routine
/*********************************************************************
************ Get FSSpec of next resolved Finder alias ***************
*********************************************************************/
static OSErr GetNextSpec(register FSSpec *theSpec)
{
register OSErr err = fnfErr;
register short aliasResFile;
register AliasHandle alias;
Boolean aliasChanged;
short resLoadState;
resLoadState = *(short *)ResLoad;
SetResLoad(FALSE);
aliasResFile = HOpenResFile(theSpec->vRefNum, theSpec->parID, &theSpec->name, fsCurPerm);
if( aliasResFile > 0 )
{
SetResLoad(TRUE);
UseResFile(aliasResFile);
alias = (AliasHandle )Get1IndResource(rAliasType, 1);
if (alias != NULL)
{
err = FollowFinderAlias(theSpec, alias, TRUE, theSpec, &aliasChanged);
if(err == noErr && aliasChanged)
{
ChangedResource((Handle )alias); /* This may fail depending on permissions */
WriteResource((Handle )alias);
}
}
else
err = resNotFound;
CloseResFile(aliasResFile);
}
SetResLoad(FALSE != resLoadState);
return(err);
}
/*********************************************************************
*************** Resolve a Finder Alias ***********************
*********************************************************************/
pascal OSErr
AL_resolveAliasFile(register FSSpec *theSpec, //I/O FSSpec for which target is returned
Boolean resolveAliasChains, //I Resolve all alias chains or just one step?
Boolean *targetIsFolder, //O Is target a folder?
Boolean *wasAliased) //O Was input FSSpec an alias?
{
register OSErr err;
register short hopCount; /* Alias file chains can have loops. A hop count prevents infinite loops */
register Boolean foundChainEnd; /* True => found a non-alias file target */
CInfoPBRec cpb; /* Parameter block used to walk the alias chain */
short savedResFile; /* I open files while pursuing an alias chain so I restore the original active resource file before returning. */
register Boolean specChanged; /* True => we may changed theSpec so if we get an error, restore theSpec. */
FSSpec savedSpec; /* in case of an error while walking an alias chain, I keep a copy of theSpec */
if( theSpec == NULL || targetIsFolder == NULL || wasAliased == NULL ) /* param check */
err = paramErr;
else
{
foundChainEnd = FALSE;
specChanged = FALSE;
*wasAliased = FALSE;
*targetIsFolder = FALSE;
savedSpec = *theSpec; /* Save a copy of theSpec in case there is a problem (optimized to have fewest copies for non-error cases) */
savedResFile = CurResFile();
cpb.hFileInfo.ioNamePtr = (StringPtr )&theSpec->name;
cpb.hFileInfo.ioFDirIndex = 0; /* Make GetCatInfo use the name string */
/* -------------------------------
** Loop looking for the target in a chain
** of alias files. I will end the chain if:
** (1) chain is too long. This is to avoid possible loops in alias chains.
** (2) encounter an error.
** (3) find the target.
** ------------------------------- */
hopCount = (resolveAliasChains ? (kResolveAliasMaxHop+1) : 1);
while( --hopCount >= 0 )
{
cpb.hFileInfo.ioVRefNum = theSpec->vRefNum;
cpb.hFileInfo.ioDirID = theSpec->parID;
cpb.hFileInfo.ioFVersNum = 0; /* MFS compatibility */
err = PBGetCatInfo(&cpb,FALSE); /* The target doesn't exist or is probably a folder or volume */
if( err == noErr )
{
if( cpb.hFileInfo.ioFlAttrib & ioDirMask ) /* cannot check alias bit before checking is folder */
{
*targetIsFolder = TRUE;
foundChainEnd = TRUE;
break;
}
else if( cpb.hFileInfo.ioFlFndrInfo.fdFlags & isAlias ) /* check Finder flags to see if this is an alias file */
{
*wasAliased = TRUE; /* Let caller know there was an alias file */
err = GetNextSpec(theSpec);
if( err == noErr ) /* if resolved an alias, then theSpec should have changed (except loops) */
specChanged = TRUE;
else
break;
}
else /* it is a file but not an alias */
{
foundChainEnd = TRUE;
break;
}
}
else
break;
}
if( err == noErr && (!foundChainEnd) ) /* if we got no error and did not reach the end of an alias chain (hop count was reached) */
if( resolveAliasChains ) /* If I was supposed to follow the chain to the end, then fnfErr */
err = fnfErr;
else
{
cpb.hFileInfo.ioVRefNum = theSpec->vRefNum;
cpb.hFileInfo.ioDirID = theSpec->parID;
cpb.hFileInfo.ioFVersNum = 0; /* MFS compatibility */
err = PBGetCatInfo(&cpb,FALSE); /* The target doesn't exist or is probably a folder or volume */
if( err == noErr )
if( cpb.hFileInfo.ioFlAttrib & ioDirMask )
*targetIsFolder = TRUE;
}
if( err != noErr && specChanged ) /* got an error and we resolved at least once then */
*theSpec = savedSpec; /* restore theSpec. This happens when chains of alias files are broken beyond the first link */
UseResFile(savedResFile); /* restore theResFile */
}
return(err);
}
/**********************************************************************
*************** Mount a foreign volume for an alias ***************
*********************************************************************/
pascal OSErr AL_aliasVolumeMount(VolumeLocation *volMntInfo, //I volume mount info
Boolean /*interact*/, //I user interaction allowed or not?
short *vRefNum, //O mounted volume's vRefNum
Boolean * /*changed*/) //O did any thing change about the mounted volume's info?
{
return VolumeMount(volMntInfo, vRefNum);
} // end of AliasVolumeMount routine
/**************************** end of alExt.c *********************************/